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/ap_file/pgo_method_type_set.h"
17
18 namespace panda::ecmascript::pgo {
19 using StringHelper = base::StringHelper;
Merge(const PGOMethodTypeSet * info)20 void PGOMethodTypeSet::Merge(const PGOMethodTypeSet *info)
21 {
22 for (const auto &fromType : info->scalarOpTypeInfos_) {
23 auto iter = scalarOpTypeInfos_.find(fromType);
24 if (iter != scalarOpTypeInfos_.end()) {
25 const_cast<ScalarOpTypeInfo &>(*iter).Merge(fromType);
26 } else {
27 scalarOpTypeInfos_.emplace(fromType);
28 }
29 }
30 for (const auto &fromType : info->rwScalarOpTypeInfos_) {
31 auto iter = rwScalarOpTypeInfos_.find(fromType);
32 if (iter != rwScalarOpTypeInfos_.end()) {
33 const_cast<RWScalarOpTypeInfo &>(*iter).Merge(fromType);
34 } else {
35 rwScalarOpTypeInfos_.emplace(fromType);
36 }
37 }
38 for (const auto &fromType : info->objDefOpTypeInfos_) {
39 AddDefine(fromType.GetOffset(), fromType.GetType());
40 }
41 }
42
SkipFromBinary(void ** buffer)43 void PGOMethodTypeSet::SkipFromBinary(void **buffer)
44 {
45 uint32_t size = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
46 for (uint32_t i = 0; i < size; i++) {
47 base::ReadBufferInSize<ScalarOpTypeInfo>(buffer);
48 }
49 }
50
ParseFromBinary(PGOContext & context,void ** addr,size_t bufferSize)51 bool PGOMethodTypeSet::ParseFromBinary(PGOContext& context, void** addr, size_t bufferSize)
52 {
53 PGOProfilerHeader *const header = context.GetHeader();
54 ASSERT(header != nullptr);
55 void* buffer = *addr;
56 uint32_t size = base::ReadBuffer<uint32_t>(addr, sizeof(uint32_t));
57 if (!base::CheckBufferBounds(*addr, buffer, bufferSize, "PGOMethodTypeSet::size")) {
58 return false;
59 }
60 if (size > MAX_METHOD_TYPE_SIZE) {
61 return false;
62 }
63 for (uint32_t i = 0; i < size; i++) {
64 auto typeInfo = base::ReadBufferInSize<TypeInfoHeader>(addr);
65 if (!base::CheckBufferBounds(*addr, buffer, bufferSize, "PGOMethodTypeSet::typeInfo")) {
66 return false;
67 }
68 if (typeInfo->GetInfoType() == InfoType::OP_TYPE) {
69 auto *scalerInfo = reinterpret_cast<ScalarOpTypeInfoRef *>(typeInfo);
70 scalarOpTypeInfos_.emplace(scalerInfo->GetOffset(),
71 PGOSampleType::ConvertFrom(context, scalerInfo->GetType()));
72 } else if (typeInfo->GetInfoType() == InfoType::DEFINE_CLASS_TYPE) {
73 auto *defineInfo = reinterpret_cast<ObjDefOpTypeInfoRef *>(typeInfo);
74 PGODefineOpType type;
75 type.ConvertFrom(context, defineInfo->GetType());
76 ObjDefOpTypeInfo info(defineInfo->GetOffset(), type);
77 objDefOpTypeInfos_.emplace(info);
78 } else if (header->SupportUseHClassType() && typeInfo->GetInfoType() == InfoType::USE_HCLASS_TYPE) {
79 auto *opTypeInfo = reinterpret_cast<RWScalarOpTypeInfoRef *>(typeInfo);
80 RWScalarOpTypeInfo info(opTypeInfo->GetOffset());
81 info.ConvertFrom(context, *opTypeInfo);
82 if (!ParseProtoChainsFromBinary(context, info, addr, buffer, bufferSize)) {
83 return false;
84 }
85 rwScalarOpTypeInfos_.emplace(info);
86 }
87 }
88 return true;
89 }
90
ParseProtoChainsFromBinary(PGOContext & context,RWScalarOpTypeInfo & info,void ** addr,void * buffer,size_t bufferSize)91 bool PGOMethodTypeSet::ParseProtoChainsFromBinary(
92 PGOContext& context, RWScalarOpTypeInfo& info, void** addr, void* buffer, size_t bufferSize)
93 {
94 for (int j = 0; j < info.GetCount(); j++) {
95 if (info.GetTypeRef().GetObjectInfo(j).GetProtoChainMarker() == ProtoChainMarker::EXSIT) {
96 auto protoChainRef = base::ReadBufferInSize<PGOProtoChainRef>(addr);
97 if (!base::CheckBufferBounds(*addr, buffer, bufferSize, "PGOMethodTypeSet::protoChainRef")) {
98 return false;
99 }
100 auto protoChain = PGOProtoChain::ConvertFrom(context, protoChainRef);
101 const_cast<PGOObjectInfo&>(info.GetTypeRef().GetObjectInfo(j)).SetProtoChain(protoChain);
102 }
103 }
104 return true;
105 }
106
ProcessToBinary(PGOContext & context,std::stringstream & stream) const107 bool PGOMethodTypeSet::ProcessToBinary(PGOContext &context, std::stringstream &stream) const
108 {
109 uint32_t number = 0;
110 std::stringstream methodStream;
111 for (auto &typeInfo : scalarOpTypeInfos_) {
112 if (!typeInfo.GetType().IsNone()) {
113 PGOSampleTypeRef sampleTypeRef = PGOSampleTypeRef::ConvertFrom(context, typeInfo.GetType());
114 ScalarOpTypeInfoRef infoRef(typeInfo.GetOffset(), sampleTypeRef);
115 methodStream.write(reinterpret_cast<char *>(&infoRef), infoRef.Size());
116 number++;
117 }
118 }
119 for (auto &typeInfo : rwScalarOpTypeInfos_) {
120 if (typeInfo.GetCount() != 0) {
121 RWScalarOpTypeInfoRef infoRef(typeInfo.GetOffset());
122 infoRef.ConvertFrom(context, typeInfo);
123 methodStream.write(reinterpret_cast<char *>(&infoRef), infoRef.Size());
124 for (int i = 0; i < typeInfo.GetCount(); i++) {
125 if (typeInfo.GetTypeRef().GetObjectInfo(i).GetProtoChainMarker() == ProtoChainMarker::EXSIT) {
126 auto protoChain = typeInfo.GetTypeRef().GetObjectInfo(i).GetProtoChain();
127 auto protoChainRef = PGOProtoChainRef::ConvertFrom(context, protoChain);
128 methodStream.write(reinterpret_cast<char *>(protoChainRef), protoChainRef->Size());
129 PGOProtoChainRef::DeleteProtoChain(protoChainRef);
130 }
131 }
132 number++;
133 }
134 }
135
136 for (const auto &typeInfo : objDefOpTypeInfos_) {
137 PGODefineOpTypeRef typeRef;
138 typeRef.ConvertFrom(context, typeInfo.GetType());
139 ObjDefOpTypeInfoRef infoRef(typeInfo.GetOffset(), typeRef);
140 methodStream.write(reinterpret_cast<char *>(&infoRef), infoRef.Size());
141 number++;
142 }
143
144 stream.write(reinterpret_cast<char *>(&number), sizeof(uint32_t));
145 if (number > 0) {
146 stream << methodStream.rdbuf();
147 return true;
148 }
149 return false;
150 }
151
ParseFromText(const std::string & typeString)152 bool PGOMethodTypeSet::ParseFromText(const std::string &typeString)
153 {
154 std::vector<std::string> typeInfoVector = StringHelper::SplitString(typeString, DumpUtils::TYPE_SEPARATOR);
155 if (typeInfoVector.size() > 0) {
156 for (const auto &iter : typeInfoVector) {
157 std::vector<std::string> typeStrings = StringHelper::SplitString(iter, DumpUtils::BLOCK_START);
158 if (typeStrings.size() < METHOD_TYPE_INFO_COUNT) {
159 return false;
160 }
161
162 uint32_t offset = 0;
163 if (!StringHelper::StrToUInt32(typeStrings[METHOD_OFFSET_INDEX].c_str(), &offset)) {
164 return false;
165 }
166 uint32_t type = 0;
167 if (!StringHelper::StrToUInt32(typeStrings[METHOD_TYPE_INDEX].c_str(), &type)) {
168 return false;
169 }
170 scalarOpTypeInfos_.emplace(offset, PGOSampleType(type));
171 }
172 }
173 return true;
174 }
175
ProcessToText(std::string & text) const176 void PGOMethodTypeSet::ProcessToText(std::string &text) const
177 {
178 bool isFirst = true;
179 for (auto typeInfoIter : scalarOpTypeInfos_) {
180 if (typeInfoIter.GetType().IsNone()) {
181 continue;
182 }
183 if (isFirst) {
184 text += DumpUtils::ARRAY_START + DumpUtils::NEW_LINE;
185 text += DumpUtils::ALIGN + DumpUtils::ALIGN;
186 isFirst = false;
187 } else {
188 text += DumpUtils::SPACE + DumpUtils::TYPE_SEPARATOR + DumpUtils::NEW_LINE;
189 text += DumpUtils::ALIGN + DumpUtils::ALIGN;
190 }
191 text += std::to_string(typeInfoIter.GetOffset());
192 text += DumpUtils::BLOCK_START;
193 text += typeInfoIter.GetType().GetTypeString();
194 }
195 for (auto rwScalarOpTypeInfoIter : rwScalarOpTypeInfos_) {
196 if (rwScalarOpTypeInfoIter.GetCount() == 0) {
197 continue;
198 }
199 if (isFirst) {
200 text += DumpUtils::ARRAY_START + DumpUtils::NEW_LINE;
201 text += DumpUtils::ALIGN + DumpUtils::ALIGN;
202 isFirst = false;
203 } else {
204 text += DumpUtils::SPACE + DumpUtils::TYPE_SEPARATOR + DumpUtils::NEW_LINE;
205 text += DumpUtils::ALIGN + DumpUtils::ALIGN;
206 }
207 rwScalarOpTypeInfoIter.ProcessToText(text);
208 }
209 for (const auto &defTypeInfoIter : objDefOpTypeInfos_) {
210 if (isFirst) {
211 text += DumpUtils::ARRAY_START + DumpUtils::NEW_LINE;
212 text += DumpUtils::ALIGN + DumpUtils::ALIGN;
213 isFirst = false;
214 } else {
215 text += DumpUtils::SPACE + DumpUtils::TYPE_SEPARATOR + DumpUtils::NEW_LINE;
216 text += DumpUtils::ALIGN + DumpUtils::ALIGN;
217 }
218 defTypeInfoIter.ProcessToText(text);
219 }
220 if (!isFirst) {
221 text += DumpUtils::NEW_LINE;
222 text += DumpUtils::ALIGN;
223 text += DumpUtils::ARRAY_END;
224 }
225 }
226
ProcessToJson(ProfileType::VariantVector & typeArray) const227 void PGOMethodTypeSet::ProcessToJson(ProfileType::VariantVector &typeArray) const
228 {
229 for (auto typeInfoIter : scalarOpTypeInfos_) {
230 if (typeInfoIter.GetType().IsNone()) {
231 continue;
232 }
233 ProfileType::StringMap type;
234 type.insert(std::make_pair(DumpJsonUtils::TYPE_OFFSET, std::to_string(typeInfoIter.GetOffset())));
235 typeInfoIter.GetType().GetTypeJson(type);
236 typeArray.push_back(type);
237 }
238 for (auto rwScalarOpTypeInfoIter : rwScalarOpTypeInfos_) {
239 if (rwScalarOpTypeInfoIter.GetCount() == 0) {
240 continue;
241 }
242 ProfileType::MapVector sameOffsetTypeArray;
243 rwScalarOpTypeInfoIter.ProcessToJson(sameOffsetTypeArray);
244 typeArray.push_back(sameOffsetTypeArray);
245 }
246 for (const auto &defTypeInfoIter : objDefOpTypeInfos_) {
247 std::vector<ProfileType::StringMap> sameOffsetTypeArray;
248 defTypeInfoIter.ProcessToJson(sameOffsetTypeArray);
249 typeArray.push_back(sameOffsetTypeArray);
250 }
251 }
252 } // namespace panda::ecmascript::pgo
253