1 /*
2 * Copyright (c) 2023 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
16 #include "ecmascript/pgo_profiler/pgo_profiler.h"
17
18 #include <chrono>
19 #include <memory>
20
21 #include "ecmascript/elements.h"
22 #include "ecmascript/ic/ic_handler.h"
23 #include "ecmascript/ic/profile_type_info.h"
24 #include "ecmascript/interpreter/interpreter-inl.h"
25 #include "ecmascript/js_function.h"
26 #include "ecmascript/js_tagged_value.h"
27 #include "ecmascript/jspandafile/js_pandafile_manager.h"
28 #include "ecmascript/log_wrapper.h"
29 #include "ecmascript/pgo_profiler/pgo_context.h"
30 #include "ecmascript/pgo_profiler/pgo_profiler_info.h"
31 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
32 #include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
33 #include "ecmascript/pgo_profiler/types/pgo_type_generator.h"
34 #include "ecmascript/pgo_profiler/pgo_utils.h"
35 #include "ecmascript/module/js_module_source_text.h"
36 #include "ecmascript/jspandafile/js_pandafile.h"
37 #include "macros.h"
38
39 namespace panda::ecmascript::pgo {
ProfileCreateObject(JSTaggedType object,ApEntityId abcId,int32_t traceId)40 void PGOProfiler::ProfileCreateObject(JSTaggedType object, ApEntityId abcId, int32_t traceId)
41 {
42 if (!isEnable_) {
43 return;
44 }
45
46 JSTaggedValue objectValue(object);
47 if (objectValue.IsJSObject()) {
48 auto hclass = objectValue.GetTaggedObject()->GetClass();
49 hclass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
50 ProfileType traceType(abcId, traceId, ProfileType::Kind::LiteralId, true);
51 InsertProfileType(JSTaggedType(hclass), JSTaggedType(hclass), traceType);
52 }
53 }
54
ProfileDefineClass(JSTaggedType ctor)55 void PGOProfiler::ProfileDefineClass(JSTaggedType ctor)
56 {
57 if (!isEnable_) {
58 return;
59 }
60 auto ctorValue = JSTaggedValue(ctor);
61 if (!ctorValue.IsJSFunction()) {
62 return;
63 }
64 auto ctorFunc = JSFunction::Cast(ctorValue.GetTaggedObject());
65 auto ctorMethodValue = ctorFunc->GetMethod();
66 if (!ctorMethodValue.IsMethod()) {
67 return;
68 }
69 auto ctorMethod = Method::Cast(ctorMethodValue);
70 auto entityId = ctorMethod->GetMethodId().GetOffset();
71
72 auto ctorMethodHClass = ctorFunc->GetClass();
73 ctorMethodHClass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
74 auto ctorRootHClass = JSTaggedType(ctorMethodHClass);
75 if (GetProfileType(ctorRootHClass, ctorRootHClass).IsNone()) {
76 ProfileType ctorProfileType(GetMethodAbcId(ctorFunc), entityId, ProfileType::Kind::ConstructorId, true);
77 InsertProfileType(ctorRootHClass, ctorRootHClass, ctorProfileType);
78 }
79
80 auto protoOrHClass = ctorFunc->GetProtoOrHClass();
81 if (protoOrHClass.IsJSHClass()) {
82 auto ihc = JSHClass::Cast(protoOrHClass.GetTaggedObject());
83 ihc->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
84 auto localRootHClass = JSTaggedType(ihc);
85 ProfileType localProfileType(GetMethodAbcId(ctorFunc), entityId, ProfileType::Kind::ClassId, true);
86 InsertProfileType(localRootHClass, localRootHClass, localProfileType);
87 protoOrHClass = ihc->GetProto();
88 }
89 if (protoOrHClass.IsJSObject()) {
90 auto prototypeHClass = protoOrHClass.GetTaggedObject()->GetClass();
91 prototypeHClass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
92 auto protoRootHClass = JSTaggedType(prototypeHClass);
93 if (GetProfileType(protoRootHClass, protoRootHClass).IsNone()) {
94 ProfileType protoProfileType(GetMethodAbcId(ctorFunc), entityId, ProfileType::Kind::PrototypeId, true);
95 InsertProfileType(protoRootHClass, protoRootHClass, protoProfileType);
96 }
97 }
98 }
99
ProfileClassRootHClass(JSTaggedType ctor,JSTaggedType rootHcValue,ProfileType::Kind kind)100 void PGOProfiler::ProfileClassRootHClass(JSTaggedType ctor, JSTaggedType rootHcValue, ProfileType::Kind kind)
101 {
102 if (!isEnable_) {
103 return;
104 }
105
106 auto ctorValue = JSTaggedValue(ctor);
107 if (!ctorValue.IsJSFunction()) {
108 return;
109 }
110 auto ctorFunc = JSFunction::Cast(ctorValue.GetTaggedObject());
111 if (!FunctionKindVerify(ctorFunc)) {
112 return;
113 }
114 auto ctorMethodValue = ctorFunc->GetMethod();
115 if (!ctorMethodValue.IsMethod()) {
116 return;
117 }
118 auto ctorMethod = Method::Cast(ctorMethodValue);
119 auto entityId = ctorMethod->GetMethodId().GetOffset();
120
121 auto rootHc = JSHClass::Cast(JSTaggedValue(rootHcValue).GetTaggedObject());
122 rootHc->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
123 if (GetProfileType(rootHcValue, rootHcValue).IsNone()) {
124 ProfileType ihcProfileType(GetMethodAbcId(ctorFunc), entityId, kind, true);
125 InsertProfileType(rootHcValue, rootHcValue, ihcProfileType);
126 }
127 }
128
ProfileDefineGetterSetter(JSHClass * receverHClass,JSHClass * holderHClass,const JSHandle<JSTaggedValue> & func,int32_t pcOffset)129 void PGOProfiler::ProfileDefineGetterSetter(
130 JSHClass *receverHClass, JSHClass *holderHClass, const JSHandle<JSTaggedValue> &func, int32_t pcOffset)
131 {
132 if (!isEnable_) {
133 return;
134 }
135 JSTaggedValue funcValue = JSTaggedValue(func.GetTaggedValue());
136 if (!funcValue.IsJSFunction()) {
137 return;
138 }
139 auto methodValue = JSFunction::Cast(funcValue)->GetMethod();
140 if (!methodValue.IsMethod()) {
141 return;
142 }
143 auto function = JSFunction::Cast(funcValue);
144 WorkNode* workNode = reinterpret_cast<WorkNode*>(function->GetWorkNodePointer());
145 if (workNode != nullptr) {
146 workNode->SetValue(JSTaggedType(function));
147 workNode->SetExtraProfileTypeInfo(pcOffset, receverHClass, holderHClass);
148 }
149 }
150
UpdateRootProfileType(JSHClass * oldHClass,JSHClass * newHClass)151 void PGOProfiler::UpdateRootProfileType(JSHClass *oldHClass, JSHClass *newHClass)
152 {
153 if (!isEnable_) {
154 return;
155 }
156 auto oldRootHClass = JSHClass::FindRootHClass(oldHClass);
157 auto iter = tracedProfiles_.find(JSTaggedType(oldRootHClass));
158 if (iter == tracedProfiles_.end()) {
159 return;
160 }
161 auto generator = iter->second;
162 auto rootProfileType = generator->GetProfileType(JSTaggedType(oldRootHClass));
163 if (rootProfileType.IsNone()) {
164 tracedProfiles_.erase(iter);
165 return;
166 }
167 tracedProfiles_.erase(iter);
168 newHClass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
169 InsertProfileType(JSTaggedType(newHClass), JSTaggedType(newHClass), rootProfileType);
170 }
171
UpdateTrackElementsKind(JSTaggedValue trackInfoVal,ElementsKind newKind)172 void PGOProfiler::UpdateTrackElementsKind(JSTaggedValue trackInfoVal, ElementsKind newKind)
173 {
174 if (trackInfoVal.IsHeapObject() && trackInfoVal.IsWeak()) {
175 auto trackInfo = TrackInfo::Cast(trackInfoVal.GetWeakReferentUnChecked());
176 auto oldKind = trackInfo->GetElementsKind();
177 if (Elements::IsGeneric(oldKind) || oldKind == newKind) {
178 return;
179 }
180 auto mixKind = Elements::MergeElementsKind(oldKind, newKind);
181 if (mixKind == oldKind) {
182 return;
183 }
184 trackInfo->SetElementsKind(mixKind);
185 auto thread = vm_->GetJSThread();
186 auto globalConst = thread->GlobalConstants();
187 auto constantId = thread->GetArrayHClassIndexMap().at(mixKind);
188 auto hclass = globalConst->GetGlobalConstantObject(static_cast<size_t>(constantId));
189 trackInfo->SetCachedHClass(vm_->GetJSThread(), hclass);
190 UpdateTrackInfo(JSTaggedValue(trackInfo));
191 }
192 }
193
UpdateTrackArrayLength(JSTaggedValue trackInfoVal,uint32_t newSize)194 void PGOProfiler::UpdateTrackArrayLength(JSTaggedValue trackInfoVal, uint32_t newSize)
195 {
196 if (trackInfoVal.IsHeapObject() && trackInfoVal.IsWeak()) {
197 auto trackInfo = TrackInfo::Cast(trackInfoVal.GetWeakReferentUnChecked());
198 uint32_t oldSize = trackInfo->GetArrayLength();
199 if (oldSize >= newSize) {
200 return;
201 }
202 trackInfo->SetArrayLength(newSize);
203 UpdateTrackInfo(JSTaggedValue(trackInfo));
204 }
205 }
206
UpdateTrackSpaceFlag(TaggedObject * object,RegionSpaceFlag spaceFlag)207 void PGOProfiler::UpdateTrackSpaceFlag(TaggedObject *object, RegionSpaceFlag spaceFlag)
208 {
209 if (!object->GetClass()->IsTrackInfoObject()) {
210 return;
211 }
212 auto trackInfo = TrackInfo::Cast(object);
213 RegionSpaceFlag oldFlag = trackInfo->GetSpaceFlag();
214 if (oldFlag == RegionSpaceFlag::IN_YOUNG_SPACE) {
215 trackInfo->SetSpaceFlag(spaceFlag);
216 }
217 }
218
UpdateTrackInfo(JSTaggedValue trackInfoVal)219 void PGOProfiler::UpdateTrackInfo(JSTaggedValue trackInfoVal)
220 {
221 if (trackInfoVal.IsHeapObject()) {
222 auto trackInfo = TrackInfo::Cast(trackInfoVal.GetTaggedObject());
223 auto func = trackInfo->GetCachedFunc();
224 if (!func.IsWeak()) {
225 return;
226 }
227 TaggedObject *object = func.GetWeakReferentUnChecked();
228 if (!object->GetClass()->IsJSFunction()) {
229 return;
230 }
231 auto method = JSFunction::Cast(object)->GetMethod();
232 auto profileTypeInfoVal = Method::Cast(method)->GetProfileTypeInfo();
233 if (profileTypeInfoVal.IsUndefined()) {
234 return;
235 }
236 auto profileTypeInfo = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject());
237 if (!profileTypeInfo->IsProfileTypeInfoPreDumped()) {
238 profileTypeInfo->SetPreDumpPeriodIndex();
239 PGOPreDump(JSTaggedType(object));
240 }
241 }
242 }
243
PGODump(JSTaggedType func)244 void PGOProfiler::PGODump(JSTaggedType func)
245 {
246 if (!isEnable_) {
247 return;
248 }
249 auto funcValue = JSTaggedValue(func);
250 if (!funcValue.IsJSFunction()) {
251 return;
252 }
253 auto methodValue = JSFunction::Cast(funcValue)->GetMethod();
254 if (!methodValue.IsMethod()) {
255 return;
256 }
257 auto function = JSFunction::Cast(funcValue);
258 auto workNode = reinterpret_cast<WorkNode *>(function->GetWorkNodePointer());
259 if (workNode == nullptr) {
260 workNode = vm_->GetNativeAreaAllocator()->New<WorkNode>(JSTaggedType(function));
261 function->SetWorkNodePointer(reinterpret_cast<uintptr_t>(workNode));
262 LockHolder lock(mutex_);
263 dumpWorkList_.PushBack(workNode);
264 } else {
265 workNode->SetValue(JSTaggedType(function));
266 auto workList = workNode->GetWorkList();
267 LockHolder lock(mutex_);
268 if (workList == &preDumpWorkList_) {
269 preDumpWorkList_.Remove(workNode);
270 }
271 if (workList != &dumpWorkList_) {
272 dumpWorkList_.PushBack(workNode);
273 }
274 }
275 if (state_ == State::STOP) {
276 state_ = State::START;
277 Taskpool::GetCurrentTaskpool()->PostTask(
278 std::make_unique<PGOProfilerTask>(this, vm_->GetJSThread()->GetThreadId()));
279 }
280 }
281
WaitPGODumpPause()282 void PGOProfiler::WaitPGODumpPause()
283 {
284 if (!isEnable_) {
285 return;
286 }
287 LockHolder lock(mutex_);
288 if (state_ == State::START) {
289 state_ = State::PAUSE;
290 condition_.Wait(&mutex_);
291 } else if (state_ == State::FORCE_SAVE) {
292 state_ = State::FORCE_SAVE_PAUSE;
293 condition_.Wait(&mutex_);
294 }
295 }
296
WaitPGODumpResume()297 void PGOProfiler::WaitPGODumpResume()
298 {
299 if (!isEnable_) {
300 return;
301 }
302 LockHolder lock(mutex_);
303 if (state_ == State::PAUSE) {
304 state_ = State::START;
305 Taskpool::GetCurrentTaskpool()->PostTask(
306 std::make_unique<PGOProfilerTask>(this, vm_->GetJSThread()->GetThreadId()));
307 } else if (state_ == State::FORCE_SAVE_PAUSE) {
308 state_ = State::FORCE_SAVE;
309 Taskpool::GetCurrentTaskpool()->PostTask(
310 std::make_unique<PGOProfilerTask>(this, vm_->GetJSThread()->GetThreadId()));
311 }
312 }
313
WaitPGODumpFinish()314 void PGOProfiler::WaitPGODumpFinish()
315 {
316 if (!isEnable_) {
317 return;
318 }
319 LockHolder lock(mutex_);
320 while (state_ == State::START) {
321 condition_.Wait(&mutex_);
322 }
323 }
324
PGOPreDump(JSTaggedType func)325 void PGOProfiler::PGOPreDump(JSTaggedType func)
326 {
327 if (!isEnable_) {
328 return;
329 }
330 auto funcValue = JSTaggedValue(func);
331 if (!funcValue.IsJSFunction()) {
332 return;
333 }
334 auto methodValue = JSFunction::Cast(funcValue)->GetMethod();
335 if (!methodValue.IsMethod()) {
336 return;
337 }
338 auto function = JSFunction::Cast(funcValue);
339 auto workNode = reinterpret_cast<WorkNode *>(function->GetWorkNodePointer());
340 if (workNode == nullptr) {
341 workNode = vm_->GetNativeAreaAllocator()->New<WorkNode>(JSTaggedType(function));
342 function->SetWorkNodePointer(reinterpret_cast<uintptr_t>(workNode));
343 LockHolder lock(mutex_);
344 preDumpWorkList_.PushBack(workNode);
345 } else {
346 workNode->SetValue(JSTaggedType(function));
347 auto workList = workNode->GetWorkList();
348 LockHolder lock(mutex_);
349 if (workList == &dumpWorkList_) {
350 workList->Remove(workNode);
351 }
352 if (workList != &preDumpWorkList_) {
353 preDumpWorkList_.PushBack(workNode);
354 }
355 }
356 }
357
UpdateExtraProfileTypeInfo(ApEntityId abcId,const CString & recordName,EntityId methodId,WorkNode * current)358 void PGOProfiler::UpdateExtraProfileTypeInfo(ApEntityId abcId,
359 const CString& recordName,
360 EntityId methodId,
361 WorkNode* current)
362 {
363 auto extraInfo = current->GetExtraProfileTypeInfo();
364 for (auto& iter: extraInfo) {
365 auto pcOffset = iter.first;
366 auto info = iter.second;
367 // skip when it is polymorphic
368 if (info.IsHole()) {
369 continue;
370 }
371 AddObjectInfo(abcId,
372 recordName,
373 methodId,
374 pcOffset,
375 info.GetReceiverHClass(),
376 info.GetReceiverHClass(),
377 info.GetHolderHClass());
378 }
379 }
380
HandlePGOPreDump()381 void PGOProfiler::HandlePGOPreDump()
382 {
383 if (!isEnable_) {
384 return;
385 }
386 DISALLOW_GARBAGE_COLLECTION;
387 preDumpWorkList_.Iterate([this](WorkNode* current) {
388 JSTaggedValue funcValue = JSTaggedValue(current->GetValue());
389 if (!funcValue.IsJSFunction()) {
390 return;
391 }
392 auto func = JSFunction::Cast(funcValue);
393 JSTaggedValue methodValue = func->GetMethod();
394 if (!methodValue.IsMethod()) {
395 return;
396 }
397 JSTaggedValue recordNameValue = Method::Cast(methodValue)->GetRecordName();
398 if (!recordNameValue.IsString()) {
399 return;
400 }
401 CString recordName = ConvertToString(recordNameValue);
402 auto abcId = GetMethodAbcId(func);
403
404 if (current->HasExtraProfileTypeInfo()) {
405 Method* method = Method::Cast(methodValue.GetTaggedObject());
406 EntityId methodId = method->GetMethodId();
407 UpdateExtraProfileTypeInfo(abcId, recordName, methodId, current);
408 }
409
410 ProfileType recordType = GetRecordProfileType(abcId, recordName);
411 recordInfos_->AddMethod(recordType, Method::Cast(methodValue), SampleMode::HOTNESS_MODE);
412 ProfileBytecode(abcId, recordName, methodValue);
413 });
414 }
415
HandlePGODump(bool force)416 void PGOProfiler::HandlePGODump(bool force)
417 {
418 if (!isEnable_) {
419 return;
420 }
421 DISALLOW_GARBAGE_COLLECTION;
422 auto current = PopFromProfileQueue();
423 while (current != nullptr) {
424 JSTaggedValue value = JSTaggedValue(current->GetValue());
425 if (value.IsUndefined()) {
426 current = PopFromProfileQueue();
427 continue;
428 }
429 if (!value.IsJSFunction()) {
430 current = PopFromProfileQueue();
431 continue;
432 }
433 auto func = JSFunction::Cast(value);
434 JSTaggedValue methodValue = func->GetMethod();
435 if (!methodValue.IsMethod()) {
436 current = PopFromProfileQueue();
437 continue;
438 }
439 JSTaggedValue recordNameValue = Method::Cast(methodValue)->GetRecordName();
440 if (!recordNameValue.IsString()) {
441 current = PopFromProfileQueue();
442 continue;
443 }
444 CString recordName = ConvertToString(recordNameValue);
445 auto abcId = GetMethodAbcId(func);
446
447 if (current->HasExtraProfileTypeInfo()) {
448 Method* method = Method::Cast(methodValue.GetTaggedObject());
449 EntityId methodId = method->GetMethodId();
450 UpdateExtraProfileTypeInfo(abcId, recordName, methodId, current);
451 }
452
453 ProfileType recordType = GetRecordProfileType(abcId, recordName);
454 if (recordInfos_->AddMethod(recordType, Method::Cast(methodValue), SampleMode::HOTNESS_MODE)) {
455 methodCount_++;
456 }
457 ProfileBytecode(abcId, recordName, methodValue);
458 current = PopFromProfileQueue();
459 }
460 if (state_ == State::PAUSE) {
461 return;
462 }
463 SaveProfiler(force);
464 }
465
SaveProfiler(bool force)466 void PGOProfiler::SaveProfiler(bool force)
467 {
468 // Merged every 50 methods and merge interval greater than minimal interval
469 auto interval = std::chrono::system_clock::now() - saveTimestamp_;
470 auto minIntervalOption = vm_->GetJSOptions().GetPGOSaveMinInterval();
471 auto mergeMinInterval = std::chrono::milliseconds(minIntervalOption * MS_PRE_SECOND);
472 if ((methodCount_ >= MERGED_EVERY_COUNT && interval > mergeMinInterval) || (force && methodCount_ > 0)) {
473 LOG_ECMA(DEBUG) << "Sample: post task to save profiler";
474 PGOProfilerManager::GetInstance()->Merge(this);
475 if (!force) {
476 PGOProfilerManager::GetInstance()->AsynSave();
477 }
478 SetSaveTimestamp(std::chrono::system_clock::now());
479 methodCount_ = 0;
480 }
481 }
482
PopFromProfileQueue()483 PGOProfiler::WorkNode* PGOProfiler::PopFromProfileQueue()
484 {
485 LockHolder lock(mutex_);
486 WorkNode* node = nullptr;
487 while (node == nullptr) {
488 if (dumpWorkList_.IsEmpty()) {
489 state_ = State::STOP;
490 condition_.SignalAll();
491 break;
492 }
493 if (state_ == State::PAUSE) {
494 condition_.SignalAll();
495 break;
496 }
497 node = dumpWorkList_.PopFront();
498 }
499 return node;
500 }
501
PausePGODump()502 bool PGOProfiler::PausePGODump()
503 {
504 if (state_ == State::PAUSE) {
505 LockHolder lock(mutex_);
506 if (state_ == State::PAUSE) {
507 condition_.SignalAll();
508 return true;
509 }
510 }
511 return false;
512 }
513
ProfileBytecode(ApEntityId abcId,const CString & recordName,JSTaggedValue value)514 void PGOProfiler::ProfileBytecode(ApEntityId abcId, const CString &recordName, JSTaggedValue value)
515 {
516 Method *method = Method::Cast(value.GetTaggedObject());
517 JSTaggedValue profileTypeInfoVal = method->GetProfileTypeInfo();
518 ASSERT(!profileTypeInfoVal.IsUndefined());
519 auto profileTypeInfo = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject());
520 auto methodId = method->GetMethodId();
521 auto pcStart = method->GetBytecodeArray();
522 auto codeSize = method->GetCodeSize();
523 BytecodeInstruction bcIns(pcStart);
524 auto bcInsLast = bcIns.JumpTo(codeSize);
525
526 while (bcIns.GetAddress() != bcInsLast.GetAddress()) {
527 if (PausePGODump()) {
528 break;
529 }
530 auto opcode = bcIns.GetOpcode();
531 auto bcOffset = bcIns.GetAddress() - pcStart;
532 auto pc = bcIns.GetAddress();
533 switch (opcode) {
534 case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
535 case EcmaOpcode::LDOBJBYNAME_IMM8_ID16: {
536 uint8_t slotId = READ_INST_8_0();
537 CHECK_SLOTID_BREAK(slotId);
538 DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
539 break;
540 }
541 case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
542 case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: {
543 uint16_t slotId = READ_INST_16_0();
544 DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
545 break;
546 }
547 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
548 case EcmaOpcode::LDTHISBYVALUE_IMM8: {
549 uint8_t slotId = READ_INST_8_0();
550 CHECK_SLOTID_BREAK(slotId);
551 DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
552 break;
553 }
554 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
555 case EcmaOpcode::LDTHISBYVALUE_IMM16: {
556 uint16_t slotId = READ_INST_16_0();
557 DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::LOAD);
558 break;
559 }
560 case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
561 case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
562 case EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8: {
563 uint8_t slotId = READ_INST_8_0();
564 CHECK_SLOTID_BREAK(slotId);
565 DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
566 break;
567 }
568 case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
569 case EcmaOpcode::STTHISBYNAME_IMM16_ID16: {
570 uint16_t slotId = READ_INST_16_0();
571 DumpICByName(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
572 break;
573 }
574 case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
575 case EcmaOpcode::STTHISBYVALUE_IMM8_V8: {
576 uint8_t slotId = READ_INST_8_0();
577 CHECK_SLOTID_BREAK(slotId);
578 DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
579 break;
580 }
581 case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
582 case EcmaOpcode::STTHISBYVALUE_IMM16_V8: {
583 uint16_t slotId = READ_INST_16_0();
584 DumpICByValue(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, BCType::STORE);
585 break;
586 }
587 // Op
588 case EcmaOpcode::ADD2_IMM8_V8:
589 case EcmaOpcode::SUB2_IMM8_V8:
590 case EcmaOpcode::MUL2_IMM8_V8:
591 case EcmaOpcode::DIV2_IMM8_V8:
592 case EcmaOpcode::MOD2_IMM8_V8:
593 case EcmaOpcode::SHL2_IMM8_V8:
594 case EcmaOpcode::SHR2_IMM8_V8:
595 case EcmaOpcode::AND2_IMM8_V8:
596 case EcmaOpcode::OR2_IMM8_V8:
597 case EcmaOpcode::XOR2_IMM8_V8:
598 case EcmaOpcode::ASHR2_IMM8_V8:
599 case EcmaOpcode::EXP_IMM8_V8:
600 case EcmaOpcode::NEG_IMM8:
601 case EcmaOpcode::NOT_IMM8:
602 case EcmaOpcode::INC_IMM8:
603 case EcmaOpcode::DEC_IMM8:
604 case EcmaOpcode::EQ_IMM8_V8:
605 case EcmaOpcode::NOTEQ_IMM8_V8:
606 case EcmaOpcode::LESS_IMM8_V8:
607 case EcmaOpcode::LESSEQ_IMM8_V8:
608 case EcmaOpcode::GREATER_IMM8_V8:
609 case EcmaOpcode::GREATEREQ_IMM8_V8:
610 case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
611 case EcmaOpcode::STRICTEQ_IMM8_V8: {
612 uint8_t slotId = READ_INST_8_0();
613 CHECK_SLOTID_BREAK(slotId);
614 DumpOpType(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
615 break;
616 }
617 // Call
618 case EcmaOpcode::CALLARG0_IMM8:
619 case EcmaOpcode::CALLARG1_IMM8_V8:
620 case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
621 case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
622 case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
623 case EcmaOpcode::CALLTHIS0_IMM8_V8:
624 case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
625 case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
626 case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
627 case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: {
628 uint8_t slotId = READ_INST_8_0();
629 CHECK_SLOTID_BREAK(slotId);
630 DumpCall(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
631 break;
632 }
633 case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8: {
634 uint8_t slotId = READ_INST_8_1();
635 CHECK_SLOTID_BREAK(slotId);
636 DumpCall(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
637 break;
638 }
639 case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
640 case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8: {
641 // no ic slot
642 break;
643 }
644 case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8: {
645 uint8_t slotId = READ_INST_8_0();
646 CHECK_SLOTID_BREAK(slotId);
647 DumpNewObjRange(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
648 break;
649 }
650 case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8: {
651 uint16_t slotId = READ_INST_16_0();
652 DumpNewObjRange(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
653 break;
654 }
655 case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8: {
656 break;
657 }
658 // Create object
659 case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8: {
660 uint8_t slotId = READ_INST_8_0();
661 CHECK_SLOTID_BREAK(slotId);
662 DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
663 break;
664 }
665 case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8: {
666 uint16_t slotId = READ_INST_16_0();
667 DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
668 break;
669 }
670 case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8: {
671 uint8_t slotId = READ_INST_8_0();
672 CHECK_SLOTID_BREAK(slotId);
673 DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
674 break;
675 }
676 case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8: {
677 uint16_t slotId = READ_INST_16_0();
678 DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
679 break;
680 }
681 case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
682 case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
683 case EcmaOpcode::CREATEEMPTYARRAY_IMM8: {
684 auto header = method->GetJSPandaFile()->GetPandaFile()->GetHeader();
685 auto traceId =
686 static_cast<int32_t>(reinterpret_cast<uintptr_t>(pc) - reinterpret_cast<uintptr_t>(header));
687 uint8_t slotId = READ_INST_8_0();
688 CHECK_SLOTID_BREAK(slotId);
689 DumpCreateObject(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, traceId);
690 break;
691 }
692 case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
693 case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
694 case EcmaOpcode::CREATEEMPTYARRAY_IMM16: {
695 auto header = method->GetJSPandaFile()->GetPandaFile()->GetHeader();
696 auto traceId =
697 static_cast<int32_t>(reinterpret_cast<uintptr_t>(pc) - reinterpret_cast<uintptr_t>(header));
698 uint16_t slotId = READ_INST_16_0();
699 DumpCreateObject(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, traceId);
700 break;
701 }
702 case EcmaOpcode::GETITERATOR_IMM8: {
703 uint8_t slotId = READ_INST_8_0();
704 CHECK_SLOTID_BREAK(slotId);
705 DumpGetIterator(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
706 break;
707 }
708 case EcmaOpcode::GETITERATOR_IMM16: {
709 uint16_t slotId = READ_INST_16_0();
710 DumpGetIterator(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
711 break;
712 }
713 // Others
714 case EcmaOpcode::INSTANCEOF_IMM8_V8: {
715 uint8_t slotId = READ_INST_8_0();
716 CHECK_SLOTID_BREAK(slotId);
717 DumpInstanceof(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
718 break;
719 }
720 case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
721 default:
722 break;
723 }
724 bcIns = bcIns.GetNext();
725 }
726 }
727
DumpICByName(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,uint32_t slotId,ProfileTypeInfo * profileTypeInfo,BCType type)728 void PGOProfiler::DumpICByName(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
729 uint32_t slotId, ProfileTypeInfo *profileTypeInfo, BCType type)
730 {
731 JSTaggedValue firstValue = profileTypeInfo->Get(slotId);
732 if (!firstValue.IsHeapObject()) {
733 if (firstValue.IsHole()) {
734 // Mega state
735 AddObjectInfoWithMega(abcId, recordName, methodId, bcOffset);
736 }
737 return;
738 }
739 if (firstValue.IsWeak()) {
740 TaggedObject *object = firstValue.GetWeakReferentUnChecked();
741 if (object->GetClass()->IsHClass()) {
742 JSTaggedValue secondValue = profileTypeInfo->Get(slotId + 1);
743 JSHClass *hclass = JSHClass::Cast(object);
744 DumpICByNameWithHandler(abcId, recordName, methodId, bcOffset, hclass, secondValue, type);
745 }
746 return;
747 }
748 DumpICByNameWithPoly(abcId, recordName, methodId, bcOffset, firstValue, type);
749 }
750
DumpICByValue(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,uint32_t slotId,ProfileTypeInfo * profileTypeInfo,BCType type)751 void PGOProfiler::DumpICByValue(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
752 uint32_t slotId, ProfileTypeInfo *profileTypeInfo, BCType type)
753 {
754 JSTaggedValue firstValue = profileTypeInfo->Get(slotId);
755 if (!firstValue.IsHeapObject()) {
756 if (firstValue.IsHole()) {
757 // Mega state
758 AddObjectInfoWithMega(abcId, recordName, methodId, bcOffset);
759 }
760 return;
761 }
762 if (firstValue.IsWeak()) {
763 TaggedObject *object = firstValue.GetWeakReferentUnChecked();
764 if (object->GetClass()->IsHClass()) {
765 JSTaggedValue secondValue = profileTypeInfo->Get(slotId + 1);
766 JSHClass *hclass = JSHClass::Cast(object);
767 DumpICByValueWithHandler(abcId, recordName, methodId, bcOffset, hclass, secondValue, type);
768 }
769 return;
770 }
771 // Check key
772 if ((firstValue.IsString() || firstValue.IsSymbol())) {
773 JSTaggedValue secondValue = profileTypeInfo->Get(slotId + 1);
774 if (secondValue.IsHeapObject()) {
775 DumpICByNameWithPoly(abcId, recordName, methodId, bcOffset, secondValue, type);
776 }
777 return;
778 }
779 // Check without key
780 DumpICByValueWithPoly(abcId, recordName, methodId, bcOffset, firstValue, type);
781 }
782
DumpICByNameWithPoly(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,JSTaggedValue cacheValue,BCType type)783 void PGOProfiler::DumpICByNameWithPoly(ApEntityId abcId,
784 const CString &recordName, EntityId methodId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type)
785 {
786 if (cacheValue.IsWeak()) {
787 return;
788 }
789 ASSERT(cacheValue.IsTaggedArray());
790 auto array = TaggedArray::Cast(cacheValue);
791 uint32_t length = array->GetLength();
792 for (uint32_t i = 0; i < length; i += 2) { // 2 means one ic, two slot
793 auto result = array->Get(i);
794 auto handler = array->Get(i + 1);
795 if (!result.IsHeapObject() || !result.IsWeak()) {
796 continue;
797 }
798 TaggedObject *object = result.GetWeakReferentUnChecked();
799 if (!object->GetClass()->IsHClass()) {
800 continue;
801 }
802 JSHClass *hclass = JSHClass::Cast(object);
803 DumpICByNameWithHandler(abcId, recordName, methodId, bcOffset, hclass, handler, type);
804 }
805 }
806
DumpICByValueWithPoly(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,JSTaggedValue cacheValue,BCType type)807 void PGOProfiler::DumpICByValueWithPoly(ApEntityId abcId,
808 const CString &recordName, EntityId methodId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type)
809 {
810 if (cacheValue.IsWeak()) {
811 return;
812 }
813 ASSERT(cacheValue.IsTaggedArray());
814 auto array = TaggedArray::Cast(cacheValue);
815 uint32_t length = array->GetLength();
816 for (uint32_t i = 0; i < length; i += 2) { // 2 means one ic, two slot
817 auto result = array->Get(i);
818 auto handler = array->Get(i + 1);
819 if (!result.IsHeapObject() || !result.IsWeak()) {
820 continue;
821 }
822 TaggedObject *object = result.GetWeakReferentUnChecked();
823 if (!object->GetClass()->IsHClass()) {
824 continue;
825 }
826 JSHClass *hclass = JSHClass::Cast(object);
827 DumpICByValueWithHandler(abcId, recordName, methodId, bcOffset, hclass, handler, type);
828 }
829 }
830
DumpICByNameWithHandler(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,JSHClass * hclass,JSTaggedValue secondValue,BCType type)831 void PGOProfiler::DumpICByNameWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId,
832 int32_t bcOffset, JSHClass *hclass, JSTaggedValue secondValue, BCType type)
833 {
834 if (type == BCType::LOAD) {
835 if (secondValue.IsInt()) {
836 auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
837 if (HandlerBase::IsNonExist(handlerInfo)) {
838 return;
839 }
840 if (HandlerBase::IsField(handlerInfo) || HandlerBase::IsAccessor(handlerInfo)) {
841 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
842 }
843 AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass);
844 } else if (secondValue.IsPrototypeHandler()) {
845 auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
846 auto cellValue = prototypeHandler->GetProtoCell();
847 ASSERT(cellValue.IsProtoChangeMarker());
848 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
849 if (cell->GetHasChanged()) {
850 return;
851 }
852 auto holder = prototypeHandler->GetHolder();
853 auto holderHClass = holder.GetTaggedObject()->GetClass();
854 JSTaggedValue handlerInfoVal = prototypeHandler->GetHandlerInfo();
855 if (!handlerInfoVal.IsInt()) {
856 return;
857 }
858 auto handlerInfo = static_cast<uint32_t>(handlerInfoVal.GetInt());
859 if (HandlerBase::IsNonExist(handlerInfo)) {
860 return;
861 }
862 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, holderHClass, holderHClass);
863 }
864 // LoadGlobal
865 return;
866 }
867 if (secondValue.IsInt()) {
868 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
869 } else if (secondValue.IsTransitionHandler()) {
870 auto transitionHandler = TransitionHandler::Cast(secondValue.GetTaggedObject());
871 auto transitionHClassVal = transitionHandler->GetTransitionHClass();
872 if (transitionHClassVal.IsJSHClass()) {
873 auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
874 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, transitionHClass);
875 }
876 } else if (secondValue.IsTransWithProtoHandler()) {
877 auto transWithProtoHandler = TransWithProtoHandler::Cast(secondValue.GetTaggedObject());
878 auto cellValue = transWithProtoHandler->GetProtoCell();
879 ASSERT(cellValue.IsProtoChangeMarker());
880 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
881 if (cell->GetHasChanged()) {
882 return;
883 }
884 auto transitionHClassVal = transWithProtoHandler->GetTransitionHClass();
885 if (transitionHClassVal.IsJSHClass()) {
886 auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
887 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, transitionHClass);
888 }
889 } else if (secondValue.IsPrototypeHandler()) {
890 auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
891 auto cellValue = prototypeHandler->GetProtoCell();
892 ASSERT(cellValue.IsProtoChangeMarker());
893 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
894 if (cell->GetHasChanged()) {
895 return;
896 }
897 auto holder = prototypeHandler->GetHolder();
898 auto holderHClass = holder.GetTaggedObject()->GetClass();
899 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, holderHClass, holderHClass);
900 } else if (secondValue.IsPropertyBox()) {
901 // StoreGlobal
902 } else if (secondValue.IsStoreTSHandler()) {
903 StoreTSHandler *storeTSHandler = StoreTSHandler::Cast(secondValue.GetTaggedObject());
904 auto cellValue = storeTSHandler->GetProtoCell();
905 ASSERT(cellValue.IsProtoChangeMarker());
906 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
907 if (cell->GetHasChanged()) {
908 return;
909 }
910 auto holder = storeTSHandler->GetHolder();
911 auto holderHClass = holder.GetTaggedObject()->GetClass();
912 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, holderHClass, holderHClass);
913 }
914 }
915
DumpICByValueWithHandler(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,JSHClass * hclass,JSTaggedValue secondValue,BCType type)916 void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId,
917 int32_t bcOffset, JSHClass *hclass, JSTaggedValue secondValue, BCType type)
918 {
919 if (type == BCType::LOAD) {
920 if (secondValue.IsInt()) {
921 auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
922 if (HandlerBase::IsNormalElement(handlerInfo) || HandlerBase::IsStringElement(handlerInfo)) {
923 if (HandlerBase::NeedSkipInPGODump(handlerInfo)) {
924 return;
925 }
926 AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass);
927 return;
928 }
929
930 if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
931 OnHeapMode onHeap = HandlerBase::IsOnHeap(handlerInfo) ? OnHeapMode::ON_HEAP : OnHeapMode::NOT_ON_HEAP;
932 AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, onHeap);
933 return;
934 }
935
936 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
937 }
938 return;
939 }
940 if (secondValue.IsInt()) {
941 auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
942 if (HandlerBase::IsNormalElement(handlerInfo) || HandlerBase::IsStringElement(handlerInfo)) {
943 AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass);
944 return;
945 }
946
947 if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
948 OnHeapMode onHeap = HandlerBase::IsOnHeap(handlerInfo) ? OnHeapMode::ON_HEAP : OnHeapMode::NOT_ON_HEAP;
949 AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, onHeap);
950 return;
951 }
952
953 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
954 } else if (secondValue.IsTransitionHandler()) {
955 auto transitionHandler = TransitionHandler::Cast(secondValue.GetTaggedObject());
956 auto transitionHClassVal = transitionHandler->GetTransitionHClass();
957
958 auto handlerInfoValue = transitionHandler->GetHandlerInfo();
959 ASSERT(handlerInfoValue.IsInt());
960 auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
961 if (transitionHClassVal.IsJSHClass()) {
962 auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
963 if (HandlerBase::IsElement(handlerInfo)) {
964 AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, transitionHClass);
965 return;
966 }
967 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, transitionHClass);
968 }
969 } else if (secondValue.IsTransWithProtoHandler()) {
970 auto transWithProtoHandler = TransWithProtoHandler::Cast(secondValue.GetTaggedObject());
971 auto transitionHClassVal = transWithProtoHandler->GetTransitionHClass();
972
973 auto handlerInfoValue = transWithProtoHandler->GetHandlerInfo();
974 ASSERT(handlerInfoValue.IsInt());
975 auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
976 if (transitionHClassVal.IsJSHClass()) {
977 auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
978 if (HandlerBase::IsElement(handlerInfo)) {
979 AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, transitionHClass);
980 return;
981 }
982 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, transitionHClass);
983 }
984 } else {
985 ASSERT(secondValue.IsPrototypeHandler());
986 PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
987 auto cellValue = prototypeHandler->GetProtoCell();
988 ASSERT(cellValue.IsProtoChangeMarker());
989 ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
990 if (cell->GetHasChanged()) {
991 return;
992 }
993 JSTaggedValue handlerInfoValue = prototypeHandler->GetHandlerInfo();
994 ASSERT(handlerInfoValue.IsInt());
995 auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
996 if (HandlerBase::IsElement(handlerInfo)) {
997 AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass, hclass);
998 return;
999 }
1000 auto holder = prototypeHandler->GetHolder();
1001 auto holderHClass = holder.GetTaggedObject()->GetClass();
1002 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, holderHClass, holderHClass);
1003 }
1004 }
1005
DumpByForce()1006 void PGOProfiler::DumpByForce()
1007 {
1008 isForce_ = true;
1009 LockHolder lock(mutex_);
1010 if (state_ == State::START) {
1011 state_ = State::FORCE_SAVE;
1012 condition_.Wait(&mutex_);
1013 } else if (state_ == State::STOP && !dumpWorkList_.IsEmpty()) {
1014 state_ = State::FORCE_SAVE;
1015 condition_.Wait(&mutex_);
1016 Taskpool::GetCurrentTaskpool()->PostTask(
1017 std::make_unique<PGOProfilerTask>(this, vm_->GetJSThread()->GetThreadId()));
1018 } else if (state_ == State::PAUSE) {
1019 state_ = State::FORCE_SAVE_PAUSE;
1020 condition_.Wait(&mutex_);
1021 }
1022 }
DumpOpType(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,uint32_t slotId,ProfileTypeInfo * profileTypeInfo)1023 void PGOProfiler::DumpOpType(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1024 uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1025 {
1026 JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
1027 if (slotValue.IsInt()) {
1028 auto type = slotValue.GetInt();
1029 ProfileType recordType = GetRecordProfileType(abcId, recordName);
1030 recordInfos_->AddType(recordType, methodId, bcOffset, PGOSampleType(type));
1031 }
1032 }
1033
FunctionKindVerify(const JSFunction * ctorFunction)1034 bool PGOProfiler::FunctionKindVerify(const JSFunction *ctorFunction)
1035 {
1036 FunctionKind kind = Method::Cast(ctorFunction->GetMethod())->GetFunctionKind();
1037 return kind == FunctionKind::BASE_CONSTRUCTOR ||
1038 kind == FunctionKind::CLASS_CONSTRUCTOR ||
1039 kind == FunctionKind::DERIVED_CONSTRUCTOR;
1040 }
1041
DumpDefineClass(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,uint32_t slotId,ProfileTypeInfo * profileTypeInfo)1042 void PGOProfiler::DumpDefineClass(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1043 uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1044 {
1045 JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
1046 if (!slotValue.IsHeapObject() || !slotValue.IsWeak()) {
1047 return;
1048 }
1049 auto object = slotValue.GetWeakReferentUnChecked();
1050 if (object->GetClass()->IsJSFunction()) {
1051 JSFunction *ctorFunction = JSFunction::Cast(object);
1052 auto ctorMethod = ctorFunction->GetMethod();
1053 if (!ctorMethod.IsMethod()) {
1054 return;
1055 }
1056 if (!FunctionKindVerify(ctorFunction)) {
1057 return;
1058 }
1059 ApEntityId ctorAbcId = GetMethodAbcId(ctorFunction);
1060 auto ctorJSMethod = Method::Cast(ctorMethod);
1061 auto ctorMethodId = ctorJSMethod->GetMethodId().GetOffset();
1062 ProfileType recordType = GetRecordProfileType(abcId, recordName);
1063
1064 auto localType = PGOSampleType::CreateProfileType(ctorAbcId, ctorMethodId, ProfileType::Kind::ClassId, true);
1065 PGODefineOpType objDefType(localType.GetProfileType());
1066 auto protoOrHClass = ctorFunction->GetProtoOrHClass();
1067 if (protoOrHClass.IsJSHClass()) {
1068 auto hclass = JSHClass::Cast(protoOrHClass.GetTaggedObject());
1069 InsertProfileType(JSTaggedType(hclass), JSTaggedType(hclass), localType.GetProfileType());
1070 recordInfos_->AddRootLayout(JSTaggedType(hclass), localType.GetProfileType());
1071 protoOrHClass = hclass->GetProto();
1072 }
1073
1074 auto ctorHClass = ctorFunction->GetJSHClass();
1075 auto ctorRootHClass = JSTaggedType(JSHClass::FindRootHClass(ctorHClass));
1076 auto ctorType = GetProfileType(ctorRootHClass, ctorRootHClass);
1077 if (ctorType.IsNone()) {
1078 LOG_ECMA(DEBUG) << "The profileType of constructor root hclass was not found.";
1079 } else {
1080 objDefType.SetCtorPt(ctorType);
1081 recordInfos_->AddRootLayout(ctorRootHClass, ctorType);
1082 }
1083
1084 if (protoOrHClass.IsJSObject()) {
1085 auto prototypeObj = JSObject::Cast(protoOrHClass);
1086 auto prototypeHClass = prototypeObj->GetClass();
1087 auto prototypeRootHClass = JSTaggedType(JSHClass::FindRootHClass(prototypeHClass));
1088 auto prototypeType = GetProfileType(prototypeRootHClass, prototypeRootHClass);
1089 if (prototypeType.IsNone()) {
1090 LOG_ECMA(DEBUG) << "The profileType of prototype root hclass was not found.";
1091 } else {
1092 objDefType.SetProtoTypePt(prototypeType);
1093 recordInfos_->AddRootLayout(prototypeRootHClass, prototypeType);
1094 }
1095 }
1096
1097 recordInfos_->AddDefine(recordType, methodId, bcOffset, objDefType);
1098 }
1099 }
1100
DumpCreateObject(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,uint32_t slotId,ProfileTypeInfo * profileTypeInfo,int32_t traceId)1101 void PGOProfiler::DumpCreateObject(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1102 uint32_t slotId, ProfileTypeInfo *profileTypeInfo, int32_t traceId)
1103 {
1104 JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
1105 if (!slotValue.IsHeapObject()) {
1106 return;
1107 }
1108 ProfileType recordType = GetRecordProfileType(abcId, recordName);
1109 if (slotValue.IsWeak()) {
1110 auto object = slotValue.GetWeakReferentUnChecked();
1111 if (object->GetClass()->IsHClass()) {
1112 auto newHClass = JSHClass::Cast(object);
1113 auto rootHClass = JSHClass::FindRootHClass(newHClass);
1114 ASSERT(rootHClass->IsJSObject());
1115 auto profileType = GetProfileType(JSTaggedType(rootHClass), JSTaggedType(rootHClass));
1116 if (profileType.IsNone()) {
1117 return;
1118 }
1119 ASSERT(profileType.GetKind() == ProfileType::Kind::LiteralId);
1120 PGOSampleType currentType(profileType);
1121 PGODefineOpType objDefType(profileType);
1122 recordInfos_->AddDefine(recordType, methodId, bcOffset, objDefType);
1123 recordInfos_->AddRootLayout(JSTaggedType(rootHClass), profileType);
1124 }
1125 } else if (slotValue.IsTrackInfoObject()) {
1126 auto currentType = PGOSampleType::CreateProfileType(abcId, traceId, ProfileType::Kind::LiteralId, true);
1127 auto profileType = currentType.GetProfileType();
1128 PGODefineOpType objDefType(profileType);
1129 TrackInfo *trackInfo = TrackInfo::Cast(slotValue.GetTaggedObject());
1130 auto elementsKind = trackInfo->GetElementsKind();
1131 objDefType.SetElementsKind(elementsKind);
1132 objDefType.SetElementsLength(trackInfo->GetArrayLength());
1133 objDefType.SetSpaceFlag(trackInfo->GetSpaceFlag());
1134 recordInfos_->AddDefine(recordType, methodId, bcOffset, objDefType);
1135 auto cachedHClass = trackInfo->GetCachedHClass();
1136 if (cachedHClass.IsJSHClass()) {
1137 auto hclass = JSHClass::Cast(cachedHClass.GetTaggedObject());
1138 recordInfos_->AddRootLayout(JSTaggedType(hclass), profileType);
1139 }
1140 }
1141 }
1142
DumpCall(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,uint32_t slotId,ProfileTypeInfo * profileTypeInfo)1143 void PGOProfiler::DumpCall(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1144 uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1145 {
1146 JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
1147 if (!slotValue.IsInt()) {
1148 return;
1149 }
1150 int calleeMethodId = slotValue.GetInt();
1151 if (calleeMethodId == 0) {
1152 return;
1153 }
1154 ProfileType::Kind kind = (calleeMethodId < 0) ? ProfileType::Kind::BuiltinFunctionId : ProfileType::Kind::MethodId;
1155 PGOSampleType type = PGOSampleType::CreateProfileType(abcId, std::abs(calleeMethodId), kind);
1156 ProfileType recordType = GetRecordProfileType(abcId, recordName);
1157 recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
1158 }
1159
DumpGetIterator(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,uint32_t slotId,ProfileTypeInfo * profileTypeInfo)1160 void PGOProfiler::DumpGetIterator(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1161 uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1162 {
1163 if (vm_->GetJSThread()->GetEnableLazyBuiltins()) {
1164 return;
1165 }
1166 JSTaggedValue value = profileTypeInfo->Get(slotId);
1167 if (!value.IsInt()) {
1168 return;
1169 }
1170 int iterKind = value.GetInt();
1171 ASSERT(iterKind <= 0);
1172 ProfileType::Kind pgoKind = ProfileType::Kind::BuiltinFunctionId;
1173 PGOSampleType type = PGOSampleType::CreateProfileType(abcId, std::abs(iterKind), pgoKind);
1174 ProfileType recordType = GetRecordProfileType(abcId, recordName);
1175 recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
1176 }
1177
DumpNewObjRange(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,uint32_t slotId,ProfileTypeInfo * profileTypeInfo)1178 void PGOProfiler::DumpNewObjRange(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1179 uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1180 {
1181 JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
1182 if (!slotValue.IsInt()) {
1183 return;
1184 }
1185 int ctorMethodId = slotValue.GetInt();
1186 if (ctorMethodId > 0) {
1187 auto type = PGOSampleType::CreateProfileType(abcId, ctorMethodId, ProfileType::Kind::ClassId, true);
1188 ProfileType recordType = GetRecordProfileType(abcId, recordName);
1189 recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
1190 }
1191 }
1192
DumpInstanceof(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,uint32_t slotId,ProfileTypeInfo * profileTypeInfo)1193 void PGOProfiler::DumpInstanceof(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1194 uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
1195 {
1196 JSTaggedValue firstValue = profileTypeInfo->Get(slotId);
1197 if (!firstValue.IsHeapObject()) {
1198 if (firstValue.IsHole()) {
1199 // Mega state
1200 AddObjectInfoWithMega(abcId, recordName, methodId, bcOffset);
1201 }
1202 return;
1203 }
1204 if (firstValue.IsWeak()) {
1205 TaggedObject *object = firstValue.GetWeakReferentUnChecked();
1206 if (object->GetClass()->IsHClass()) {
1207 JSHClass *hclass = JSHClass::Cast(object);
1208 // Since pgo does not support symbol, we choose to return if hclass having @@hasInstance
1209 JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
1210 JSTaggedValue key = env->GetHasInstanceSymbol().GetTaggedValue();
1211 JSHClass *functionPrototypeHC = JSObject::Cast(env->GetFunctionPrototype().GetTaggedValue())->GetClass();
1212 JSTaggedValue foundHClass = TryFindKeyInPrototypeChain(object, hclass, key);
1213 if (!foundHClass.IsUndefined() && JSHClass::Cast(foundHClass.GetTaggedObject()) != functionPrototypeHC) {
1214 return;
1215 }
1216 AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
1217 }
1218 return;
1219 }
1220 // Poly Not Consider now
1221 return;
1222 }
1223
UpdateLayout(JSHClass * hclass)1224 void PGOProfiler::UpdateLayout(JSHClass *hclass)
1225 {
1226 auto parentHClass = hclass->GetParent();
1227 if (parentHClass.IsJSHClass()) {
1228 UpdateTranstionLayout(JSHClass::Cast(parentHClass.GetTaggedObject()), hclass);
1229 } else {
1230 auto rootHClass = JSHClass::FindRootHClass(hclass);
1231 auto rootHClassVal = JSTaggedType(rootHClass);
1232 auto rootType = GetProfileType(rootHClassVal, rootHClassVal);
1233 if (rootType.IsNone()) {
1234 return;
1235 }
1236
1237 auto prototypeHClass = JSHClass::FindProtoRootHClass(rootHClass);
1238 if (prototypeHClass.IsJSHClass()) {
1239 auto prototypeValue = prototypeHClass.GetRawData();
1240 auto prototypeType = GetProfileType(prototypeValue, prototypeValue);
1241 if (!prototypeType.IsNone()) {
1242 recordInfos_->AddRootPtType(rootType, prototypeType);
1243 UpdateLayout(JSHClass::Cast(prototypeHClass.GetTaggedObject()));
1244 }
1245 }
1246
1247 auto curType = GetOrInsertProfileType(rootHClassVal, JSTaggedType(hclass));
1248 recordInfos_->UpdateLayout(rootType, JSTaggedType(hclass), curType);
1249 }
1250 }
1251
UpdateTranstionLayout(JSHClass * parent,JSHClass * child)1252 void PGOProfiler::UpdateTranstionLayout(JSHClass *parent, JSHClass *child)
1253 {
1254 auto rootHClass = JSHClass::FindRootHClass(parent);
1255 auto rootHClassVal = JSTaggedType(rootHClass);
1256 auto rootType = GetProfileType(rootHClassVal, rootHClassVal);
1257 if (rootType.IsNone()) {
1258 return;
1259 }
1260 auto curHClass = JSTaggedType(child);
1261 auto curType = GetOrInsertProfileType(rootHClassVal, curHClass);
1262 CVector<JSTaggedType> hclassVec;
1263 CVector<ProfileType> typeVec;
1264 hclassVec.push_back(curHClass);
1265 typeVec.push_back(curType);
1266
1267 auto parentHClass = JSTaggedValue(parent);
1268 auto parentHCValue = JSTaggedType(parent);
1269 auto parentType = GetOrInsertProfileType(rootHClassVal, parentHCValue);
1270 while (parentHClass.IsJSHClass()) {
1271 parentHClass = JSHClass::Cast(parentHClass.GetTaggedObject())->GetParent();
1272 if (!parentHClass.IsJSHClass()) {
1273 break;
1274 }
1275 hclassVec.push_back(parentHCValue);
1276 typeVec.push_back(parentType);
1277 parentHCValue = JSTaggedType(parentHClass.GetTaggedObject());
1278 parentType = GetOrInsertProfileType(rootHClassVal, parentHCValue);
1279 }
1280
1281 auto prototypeHClass = JSHClass::FindProtoRootHClass(rootHClass);
1282 if (prototypeHClass.IsJSHClass()) {
1283 auto prototypeValue = prototypeHClass.GetRawData();
1284 auto prototypeType = GetProfileType(prototypeValue, prototypeValue);
1285 if (!prototypeType.IsNone()) {
1286 recordInfos_->AddRootPtType(rootType, prototypeType);
1287 UpdateLayout(JSHClass::Cast(prototypeHClass.GetTaggedObject()));
1288 }
1289 }
1290
1291 int32_t size = static_cast<int32_t>(hclassVec.size());
1292 for (int32_t i = size - 1; i >= 0; i--) {
1293 curHClass = hclassVec[i];
1294 curType = typeVec[i];
1295 recordInfos_->UpdateTransitionLayout(rootType, parentHCValue, parentType, curHClass, curType);
1296 parentHCValue = curHClass;
1297 parentType = curType;
1298 }
1299 }
1300
AddTranstionObjectInfo(ProfileType recordType,EntityId methodId,int32_t bcOffset,JSHClass * receiver,JSHClass * hold,JSHClass * holdTra)1301 void PGOProfiler::AddTranstionObjectInfo(
1302 ProfileType recordType, EntityId methodId, int32_t bcOffset, JSHClass *receiver, JSHClass *hold, JSHClass *holdTra)
1303 {
1304 auto receiverRootHClass = JSTaggedType(JSHClass::FindRootHClass(receiver));
1305 auto receiverRootType = GetProfileType(receiverRootHClass, receiverRootHClass);
1306 if (receiverRootType.IsNone()) {
1307 return;
1308 }
1309 auto receiverType = GetOrInsertProfileType(receiverRootHClass, JSTaggedType(receiver));
1310
1311 auto holdRootHClass = JSTaggedType(JSHClass::FindRootHClass(hold));
1312 auto holdRootType = GetProfileType(holdRootHClass, holdRootHClass);
1313 if (holdRootType.IsNone()) {
1314 return;
1315 }
1316 auto holdType = GetOrInsertProfileType(holdRootHClass, JSTaggedType(hold));
1317
1318 auto holdTraRootHClass = JSTaggedType(JSHClass::FindRootHClass(holdTra));
1319 auto holdTraRootType = GetProfileType(holdTraRootHClass, holdTraRootHClass);
1320 if (holdTraRootType.IsNone()) {
1321 return;
1322 }
1323 auto holdTraType = GetOrInsertProfileType(holdTraRootHClass, JSTaggedType(holdTra));
1324
1325 if (receiver != hold) {
1326 UpdateLayout(receiver);
1327 }
1328
1329 if (holdType == holdTraType) {
1330 UpdateLayout(hold);
1331 } else {
1332 UpdateTranstionLayout(hold, holdTra);
1333 }
1334
1335 PGOObjectInfo info(receiverRootType, receiverType, holdRootType, holdType, holdTraRootType, holdTraType);
1336 UpdatePrototypeChainInfo(receiver, hold, info);
1337 recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1338 }
1339
AddObjectInfo(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,JSHClass * receiver,JSHClass * hold,JSHClass * holdTra)1340 void PGOProfiler::AddObjectInfo(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
1341 JSHClass *receiver, JSHClass *hold, JSHClass *holdTra)
1342 {
1343 ProfileType recordType = GetRecordProfileType(abcId, recordName);
1344 AddTranstionObjectInfo(recordType, methodId, bcOffset, receiver, hold, holdTra);
1345 }
1346
UpdatePrototypeChainInfo(JSHClass * receiver,JSHClass * holder,PGOObjectInfo & info)1347 void PGOProfiler::UpdatePrototypeChainInfo(JSHClass *receiver, JSHClass *holder, PGOObjectInfo &info)
1348 {
1349 if (receiver == holder) {
1350 return;
1351 }
1352
1353 std::vector<std::pair<ProfileType, ProfileType>> protoChain;
1354 JSTaggedValue proto = JSHClass::FindProtoHClass(receiver);
1355 while (proto.IsJSHClass()) {
1356 auto protoHClass = JSHClass::Cast(proto.GetTaggedObject());
1357 if (protoHClass == holder) {
1358 break;
1359 }
1360 auto protoRootHClass = JSTaggedType(JSHClass::FindRootHClass(protoHClass));
1361 auto protoRootType = GetProfileType(protoRootHClass, protoRootHClass);
1362 if (protoRootType.IsNone()) {
1363 break;
1364 }
1365 auto protoType = GetOrInsertProfileType(protoRootHClass, JSTaggedType(protoHClass));
1366 protoChain.emplace_back(protoRootType, protoType);
1367 proto = JSHClass::FindProtoHClass(protoHClass);
1368 }
1369 if (!protoChain.empty()) {
1370 info.AddPrototypePt(protoChain);
1371 }
1372 }
1373
AddObjectInfoWithMega(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset)1374 void PGOProfiler::AddObjectInfoWithMega(
1375 ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset)
1376 {
1377 auto megaType = ProfileType::CreateMegeType();
1378 PGOObjectInfo info(megaType, megaType, megaType, megaType, megaType, megaType);
1379 ProfileType recordType = GetRecordProfileType(abcId, recordName);
1380 recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1381 }
1382
AddBuiltinsInfo(ApEntityId abcId,const CString & recordName,EntityId methodId,int32_t bcOffset,JSHClass * receiver,JSHClass * transitionHClass,OnHeapMode onHeap)1383 void PGOProfiler::AddBuiltinsInfo(
1384 ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, JSHClass *receiver,
1385 JSHClass *transitionHClass, OnHeapMode onHeap)
1386 {
1387 ProfileType recordType = GetRecordProfileType(abcId, recordName);
1388 if (receiver->IsJSArray()) {
1389 auto type = receiver->GetObjectType();
1390 auto elementsKind = receiver->GetElementsKind();
1391 auto transitionElementsKind = transitionHClass->GetElementsKind();
1392 auto profileType = ProfileType::CreateBuiltinsArray(abcId, type, elementsKind, transitionElementsKind);
1393 PGOObjectInfo info(profileType);
1394 recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1395 } else if (receiver->IsTypedArray()) {
1396 JSType jsType = receiver->GetObjectType();
1397 auto profileType = ProfileType::CreateBuiltinsTypedArray(abcId, jsType, onHeap);
1398 PGOObjectInfo info(profileType);
1399 recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1400 } else if (receiver->IsString()) {
1401 auto type = receiver->GetObjectType();
1402 PGOObjectInfo info(ProfileType::CreateBuiltins(abcId, type));
1403 recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
1404 }
1405 }
1406
InsertProfileType(JSTaggedType root,JSTaggedType child,ProfileType traceType)1407 void PGOProfiler::InsertProfileType(JSTaggedType root, JSTaggedType child, ProfileType traceType)
1408 {
1409 if (!isEnable_) {
1410 return;
1411 }
1412
1413 auto iter = tracedProfiles_.find(root);
1414 if (iter != tracedProfiles_.end()) {
1415 auto generator = iter->second;
1416 generator->InsertProfileType(child, traceType);
1417 } else {
1418 auto generator = vm_->GetNativeAreaAllocator()->New<PGOTypeGenerator>();
1419 generator->InsertProfileType(child, traceType);
1420 tracedProfiles_.emplace(root, generator);
1421 }
1422 }
1423
GetProfileType(JSTaggedType root,JSTaggedType child)1424 ProfileType PGOProfiler::GetProfileType(JSTaggedType root, JSTaggedType child)
1425 {
1426 auto iter = tracedProfiles_.find(root);
1427 if (iter == tracedProfiles_.end()) {
1428 return ProfileType::PROFILE_TYPE_NONE;
1429 }
1430 auto generator = iter->second;
1431 return generator->GetProfileType(child);
1432 }
1433
GetOrInsertProfileType(JSTaggedType root,JSTaggedType child)1434 ProfileType PGOProfiler::GetOrInsertProfileType(JSTaggedType root, JSTaggedType child)
1435 {
1436 auto iter = tracedProfiles_.find(root);
1437 if (iter == tracedProfiles_.end()) {
1438 return ProfileType::PROFILE_TYPE_NONE;
1439 }
1440 auto generator = iter->second;
1441 auto rootType = generator->GetProfileType(root);
1442 if (rootType.IsNone()) {
1443 return ProfileType::PROFILE_TYPE_NONE;
1444 }
1445 return generator->GenerateProfileType(rootType, child);
1446 }
1447
ProcessReferences(const WeakRootVisitor & visitor)1448 void PGOProfiler::ProcessReferences(const WeakRootVisitor &visitor)
1449 {
1450 if (!isEnable_) {
1451 return;
1452 }
1453 for (auto iter = tracedProfiles_.begin(); iter != tracedProfiles_.end();) {
1454 JSTaggedType object = iter->first;
1455 auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
1456 if (fwd == nullptr) {
1457 vm_->GetNativeAreaAllocator()->Delete(iter->second);
1458 iter = tracedProfiles_.erase(iter);
1459 continue;
1460 }
1461 if (fwd != reinterpret_cast<TaggedObject *>(object)) {
1462 UNREACHABLE();
1463 }
1464 auto generator = iter->second;
1465 generator->ProcessReferences(visitor);
1466 ++iter;
1467 }
1468 preDumpWorkList_.Iterate([this, &visitor](WorkNode *node) {
1469 auto object = reinterpret_cast<TaggedObject *>(node->GetValue());
1470 auto fwd = visitor(object);
1471 if (fwd == nullptr) {
1472 preDumpWorkList_.Remove(node);
1473 vm_->GetNativeAreaAllocator()->Delete(node);
1474 return;
1475 }
1476 if (fwd != object) {
1477 node->SetValue(JSTaggedType(fwd));
1478 }
1479 node->ProcessExtraProfileTypeInfo(visitor);
1480 });
1481 }
1482
Iterate(const RootVisitor & visitor)1483 void PGOProfiler::Iterate(const RootVisitor &visitor)
1484 {
1485 if (!isEnable_) {
1486 return;
1487 }
1488 // If the IC of the method is stable, the current design forces the dump data.
1489 // Must pause dump during GC.
1490 dumpWorkList_.Iterate([&visitor](WorkNode* node) {
1491 visitor(Root::ROOT_VM, ObjectSlot(node->GetValueAddr()));
1492 node->IterateExtraProfileTypeInfo(visitor);
1493 });
1494 }
1495
PGOProfiler(EcmaVM * vm,bool isEnable)1496 PGOProfiler::PGOProfiler(EcmaVM *vm, bool isEnable) : vm_(vm), isEnable_(isEnable)
1497 {
1498 if (isEnable_) {
1499 recordInfos_ = std::make_unique<PGORecordDetailInfos>(0);
1500 }
1501 };
1502
~PGOProfiler()1503 PGOProfiler::~PGOProfiler()
1504 {
1505 Reset(false);
1506 for (auto iter : tracedProfiles_) {
1507 vm_->GetNativeAreaAllocator()->Delete(iter.second);
1508 }
1509 }
1510
Reset(bool isEnable)1511 void PGOProfiler::Reset(bool isEnable)
1512 {
1513 isEnable_ = isEnable;
1514 methodCount_ = 0;
1515 if (recordInfos_) {
1516 recordInfos_->Clear();
1517 } else {
1518 if (isEnable_) {
1519 recordInfos_ = std::make_unique<PGORecordDetailInfos>(0);
1520 }
1521 }
1522 }
1523
GetMethodAbcId(JSFunction * jsFunction)1524 ApEntityId PGOProfiler::GetMethodAbcId(JSFunction *jsFunction)
1525 {
1526 CString pfName;
1527 auto jsMethod = jsFunction->GetMethod();
1528 if (jsMethod.IsMethod()) {
1529 const auto *pf = Method::Cast(jsMethod)->GetJSPandaFile();
1530 if (pf != nullptr) {
1531 pfName = pf->GetJSPandaFileDesc();
1532 }
1533 }
1534 ApEntityId abcId(0);
1535 if (!PGOProfilerManager::GetInstance()->GetPandaFileId(pfName, abcId) && !pfName.empty()) {
1536 LOG_ECMA(ERROR) << "Get method abc id failed. abcName: " << pfName;
1537 }
1538 return abcId;
1539 }
1540
GetRecordProfileType(JSFunction * jsFunction,const CString & recordName)1541 ProfileType PGOProfiler::GetRecordProfileType(JSFunction *jsFunction, const CString &recordName)
1542 {
1543 CString pfName;
1544 auto jsMethod = jsFunction->GetMethod();
1545 if (jsMethod.IsMethod()) {
1546 const auto *pf = Method::Cast(jsMethod)->GetJSPandaFile();
1547 if (pf != nullptr) {
1548 pfName = pf->GetJSPandaFileDesc();
1549 }
1550 }
1551 const auto &pf = JSPandaFileManager::GetInstance()->FindJSPandaFile(pfName);
1552 if (pf == nullptr) {
1553 LOG_ECMA(ERROR) << "Get record profile type failed. pf is null, pfName: " << pfName
1554 << ", recordName: " << recordName;
1555 return ProfileType::PROFILE_TYPE_NONE;
1556 }
1557 return GetRecordProfileType(pf, GetMethodAbcId(jsFunction), recordName);
1558 }
1559
GetRecordProfileType(ApEntityId abcId,const CString & recordName)1560 ProfileType PGOProfiler::GetRecordProfileType(ApEntityId abcId, const CString &recordName)
1561 {
1562 CString pfDesc;
1563 PGOProfilerManager::GetInstance()->GetPandaFileDesc(abcId, pfDesc);
1564 const auto &pf = JSPandaFileManager::GetInstance()->FindJSPandaFile(pfDesc);
1565 if (pf == nullptr) {
1566 LOG_ECMA(ERROR) << "Get record profile type failed. pf is null, pfDesc: " << pfDesc
1567 << ", recordName: " << recordName;
1568 return ProfileType::PROFILE_TYPE_NONE;
1569 }
1570 return GetRecordProfileType(pf, abcId, recordName);
1571 }
1572
GetRecordProfileType(const std::shared_ptr<JSPandaFile> & pf,ApEntityId abcId,const CString & recordName)1573 ProfileType PGOProfiler::GetRecordProfileType(const std::shared_ptr<JSPandaFile> &pf, ApEntityId abcId,
1574 const CString &recordName)
1575 {
1576 ASSERT(pf != nullptr);
1577 JSRecordInfo recordInfo;
1578 bool hasRecord = pf->CheckAndGetRecordInfo(recordName, recordInfo);
1579 if (!hasRecord) {
1580 LOG_ECMA(ERROR) << "Get recordInfo failed. recordName: " << recordName;
1581 return ProfileType::PROFILE_TYPE_NONE;
1582 }
1583 ProfileType recordType {0};
1584 if (pf->IsBundlePack()) {
1585 ASSERT(recordName == JSPandaFile::ENTRY_FUNCTION_NAME);
1586 recordType = CreateRecordProfileType(abcId, ProfileType::RECORD_ID_FOR_BUNDLE);
1587 recordInfos_->GetRecordPool()->Add(recordType, recordName);
1588 return recordType;
1589 }
1590 if (recordInfo.classId != JSPandaFile::CLASSID_OFFSET_NOT_FOUND) {
1591 recordType = CreateRecordProfileType(abcId, recordInfo.classId);
1592 recordInfos_->GetRecordPool()->Add(recordType, recordName);
1593 return recordType;
1594 }
1595 LOG_ECMA(ERROR) << "Invalid classId, skip it. recordName: " << recordName << ", isCjs: " << recordInfo.isCjs
1596 << ", isJson: " << recordInfo.isJson;
1597 return ProfileType::PROFILE_TYPE_NONE;
1598 }
1599
PushBack(WorkNode * node)1600 void PGOProfiler::WorkList::PushBack(WorkNode *node)
1601 {
1602 if (last_ == nullptr) {
1603 first_ = node;
1604 last_ = node;
1605 } else {
1606 last_->SetNext(node);
1607 node->SetPrev(last_);
1608 last_ = node;
1609 }
1610 node->SetWorkList(this);
1611 }
1612
PopFront()1613 PGOProfiler::WorkNode *PGOProfiler::WorkList::PopFront()
1614 {
1615 WorkNode *result = nullptr;
1616 if (first_ != nullptr) {
1617 result = first_;
1618 if (first_->GetNext() != nullptr) {
1619 first_ = first_->GetNext();
1620 first_->SetPrev(nullptr);
1621 } else {
1622 first_ = nullptr;
1623 last_ = nullptr;
1624 }
1625 result->SetNext(nullptr);
1626 result->SetWorkList(nullptr);
1627 }
1628 return result;
1629 }
1630
Remove(WorkNode * node)1631 void PGOProfiler::WorkList::Remove(WorkNode *node)
1632 {
1633 if (node->GetPrev() != nullptr) {
1634 node->GetPrev()->SetNext(node->GetNext());
1635 }
1636 if (node->GetNext() != nullptr) {
1637 node->GetNext()->SetPrev(node->GetPrev());
1638 }
1639 if (node == first_) {
1640 first_ = node->GetNext();
1641 }
1642 if (node == last_) {
1643 last_ = node->GetPrev();
1644 }
1645 node->SetPrev(nullptr);
1646 node->SetNext(nullptr);
1647 node->SetWorkList(nullptr);
1648 }
1649
Iterate(Callback callback) const1650 void PGOProfiler::WorkList::Iterate(Callback callback) const
1651 {
1652 auto current = first_;
1653 while (current != nullptr) {
1654 auto next = current->GetNext();
1655 callback(current);
1656 current = next;
1657 }
1658 }
1659
CreateRecordProfileType(ApEntityId abcId,ApEntityId classId)1660 ProfileType PGOProfiler::CreateRecordProfileType(ApEntityId abcId, ApEntityId classId)
1661 {
1662 return {abcId, classId, ProfileType::Kind::RecordClassId};
1663 }
1664
TryFindKeyInPrototypeChain(TaggedObject * currObj,JSHClass * currHC,JSTaggedValue key)1665 JSTaggedValue PGOProfiler::TryFindKeyInPrototypeChain(TaggedObject *currObj, JSHClass *currHC, JSTaggedValue key)
1666 {
1667 // This is a temporary solution for Instanceof Only!
1668 // Do NOT use this function for other purpose.
1669 if (currHC->IsDictionaryMode()) {
1670 return JSTaggedValue(currHC);
1671 }
1672 while (!JSTaggedValue(currHC).IsUndefinedOrNull()) {
1673 if (LIKELY(!currHC->IsDictionaryMode())) {
1674 int entry = JSHClass::FindPropertyEntry(vm_->GetJSThread(), currHC, key);
1675 if (entry != -1) {
1676 return JSTaggedValue(currHC);
1677 }
1678 } else {
1679 TaggedArray *array = TaggedArray::Cast(JSObject::Cast(currObj)->GetProperties().GetTaggedObject());
1680 ASSERT(array->IsDictionaryMode());
1681 NameDictionary *dict = NameDictionary::Cast(array);
1682 int entry = dict->FindEntry(key);
1683 if (entry != -1) {
1684 return JSTaggedValue(currHC);
1685 }
1686 }
1687 currObj = currHC->GetProto().GetTaggedObject();
1688 if (JSTaggedValue(currObj).IsUndefinedOrNull()) {
1689 break;
1690 }
1691 currHC = currObj->GetClass();
1692 }
1693 return JSTaggedValue::Undefined();
1694 }
1695 } // namespace panda::ecmascript::pgo
1696