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/compiler/pgo_type/pgo_type_recorder.h"
17 #include "ecmascript/jspandafile/js_pandafile_manager.h"
18
19 namespace panda::ecmascript::kungfu {
20 using PGOType = pgo::PGOType;
21 using PGOObjectInfo = pgo::PGOObjectInfo;
22
PGOTypeRecorder(const PGOProfilerDecoder & decoder)23 PGOTypeRecorder::PGOTypeRecorder(const PGOProfilerDecoder &decoder) : decoder_(decoder) {}
24
PGOTypeRecorder(const PGOProfilerDecoder & decoder,const JSPandaFile * jsPandaFile,uint32_t methodOffset)25 PGOTypeRecorder::PGOTypeRecorder(
26 const PGOProfilerDecoder &decoder, const JSPandaFile *jsPandaFile, uint32_t methodOffset)
27 : decoder_(decoder)
28 {
29 auto callback = [this] (uint32_t offset, const PGOType *type) {
30 if (type->IsScalarOpType()) {
31 bcOffsetPGOOpTypeMap_.emplace(offset, reinterpret_cast<const PGOSampleType *>(type));
32 } else if (type->IsRwOpType()) {
33 bcOffsetPGORwTypeMap_[offset] = reinterpret_cast<const PGORWOpType *>(type);
34 } else if (type->IsDefineOpType()) {
35 bcOffsetPGODefOpTypeMap_.emplace(offset, reinterpret_cast<const PGODefineOpType *>(type));
36 } else {
37 UNREACHABLE();
38 }
39 };
40 const CString recordName = MethodLiteral::GetRecordName(jsPandaFile, EntityId(methodOffset));
41 auto methodLiteral = jsPandaFile->FindMethodLiteral(methodOffset);
42 decoder.GetTypeInfo(jsPandaFile, recordName, methodLiteral, callback);
43 }
44
GetElementsKindsForUser(int32_t offset) const45 std::vector<ElementsKind> PGOTypeRecorder::GetElementsKindsForUser(int32_t offset) const
46 {
47 std::vector<ElementsKind> elementsKinds;
48 if (bcOffsetPGORwTypeMap_.find(offset) == bcOffsetPGORwTypeMap_.end()) {
49 elementsKinds.emplace_back(ElementsKind::GENERIC);
50 return elementsKinds;
51 }
52
53 PGORWOpType rwType = *(bcOffsetPGORwTypeMap_.at(offset));
54 if (rwType.GetCount() == 0) {
55 elementsKinds.emplace_back(ElementsKind::GENERIC);
56 return elementsKinds;
57 }
58 for (uint32_t i = 0; i < rwType.GetCount(); i++) {
59 PGOObjectInfo info = rwType.GetObjectInfo(i);
60 auto profileType = info.GetProfileType();
61 if (profileType.IsBuiltinsArray()) {
62 elementsKinds.emplace_back(profileType.GetElementsKindBeforeTransition());
63 continue;
64 }
65 }
66
67 return elementsKinds;
68 }
69
GetTransitionElementsKindsForUser(int32_t offset) const70 std::vector<ElementsKind> PGOTypeRecorder::GetTransitionElementsKindsForUser(int32_t offset) const
71 {
72 std::vector<ElementsKind> elementsKinds;
73 if (bcOffsetPGORwTypeMap_.find(offset) == bcOffsetPGORwTypeMap_.end()) {
74 elementsKinds.emplace_back(ElementsKind::GENERIC);
75 return elementsKinds;
76 }
77
78 PGORWOpType rwType = *(bcOffsetPGORwTypeMap_.at(offset));
79 if (rwType.GetCount() == 0) {
80 elementsKinds.emplace_back(ElementsKind::GENERIC);
81 return elementsKinds;
82 }
83 for (uint32_t i = 0; i < rwType.GetCount(); i++) {
84 PGOObjectInfo info = rwType.GetObjectInfo(i);
85 auto profileType = info.GetProfileType();
86 if (profileType.IsBuiltinsArray()) {
87 elementsKinds.emplace_back(profileType.GetElementsKindAfterTransition());
88 continue;
89 }
90 }
91
92 return elementsKinds;
93 }
94
GetElementsKindForCreater(int32_t offset) const95 ElementsKind PGOTypeRecorder::GetElementsKindForCreater(int32_t offset) const
96 {
97 if (bcOffsetPGODefOpTypeMap_.find(offset) != bcOffsetPGODefOpTypeMap_.end()) {
98 const auto iter = bcOffsetPGODefOpTypeMap_.at(offset);
99 return iter->GetElementsKind();
100 }
101 // When ElementsKind switch turned on, it should be GENERIC
102 return ElementsKind::NONE;
103 }
104
GetElementsLength(int32_t offset) const105 uint32_t PGOTypeRecorder::GetElementsLength(int32_t offset) const
106 {
107 if (bcOffsetPGODefOpTypeMap_.find(offset) != bcOffsetPGODefOpTypeMap_.end()) {
108 const auto iter = bcOffsetPGODefOpTypeMap_.at(offset);
109 return iter->GetElementsLength();
110 }
111 return 0;
112 }
113
GetRegionSpaceFlag(int32_t offset) const114 RegionSpaceFlag PGOTypeRecorder::GetRegionSpaceFlag(int32_t offset) const
115 {
116 if (bcOffsetPGODefOpTypeMap_.find(offset) != bcOffsetPGODefOpTypeMap_.end()) {
117 const auto iter = bcOffsetPGODefOpTypeMap_.at(offset);
118 return iter->GetSpaceFlag();
119 }
120 return RegionSpaceFlag::IN_YOUNG_SPACE;
121 }
122
GetPGOType(int32_t offset) const123 PGOTypeRef PGOTypeRecorder::GetPGOType(int32_t offset) const
124 {
125 if (bcOffsetPGOOpTypeMap_.find(offset) != bcOffsetPGOOpTypeMap_.end()) {
126 return PGOTypeRef(bcOffsetPGOOpTypeMap_.at(offset));
127 } else if (bcOffsetPGORwTypeMap_.find(offset) != bcOffsetPGORwTypeMap_.end()) {
128 return PGOTypeRef(bcOffsetPGORwTypeMap_.at(offset));
129 } else if (bcOffsetPGODefOpTypeMap_.find(offset) != bcOffsetPGODefOpTypeMap_.end()) {
130 return PGOTypeRef(bcOffsetPGODefOpTypeMap_.at(offset));
131 }
132 return PGOTypeRef::NoneType();
133 }
134
IsInsufficientProfile(int32_t offset) const135 bool PGOTypeRecorder::IsInsufficientProfile(int32_t offset) const
136 {
137 // Normally, JIT will definitely enable profiling, and the bytecode will definitely be able to find the
138 // corresponding information in bcOffsetBoolmap_.
139 if (bcOffsetBoolMap_.find(offset) != bcOffsetBoolMap_.end()) {
140 return bcOffsetBoolMap_.at(offset);
141 } else {
142 // When JIT does not open profiling, it is necessary to discard the tag to avoid generating unexpected Deopt.
143 return false;
144 }
145 }
146
IsValidPt(ProfileType type) const147 bool PGOTypeRecorder::IsValidPt(ProfileType type) const
148 {
149 auto abcId = type.GetAbcId();
150 CString abcName;
151 if (decoder_.GetAbcNameById(abcId, abcName)) {
152 CString normalizedFileName = JSPandaFile::GetNormalizedFileDesc(abcName);
153 if (JSPandaFileManager::GetInstance()->FindJSPandaFileByNormalizedName(normalizedFileName) == nullptr) {
154 LOG_ECMA(DEBUG) << "ProfileType is invalid:" << type.GetTypeString() << ", abcName:" << abcName
155 << ", normalize name:" << normalizedFileName;
156 return false;
157 }
158 return true;
159 }
160 LOG_ECMA(DEBUG) << "ProfileType is invalid:" << type.GetTypeString();
161 return false;
162 }
163 } // namespace panda::ecmascript
164