• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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