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_parser.h"
17
18 namespace panda::ecmascript::kungfu {
19 using ProtoTransType = PGOTypeManager::ProtoTransType;
Parse(const BytecodeInfoCollector & collector,const PGOTypeRecorder & typeRecorder,const PGOHClassGenerator & generator,uint32_t methodOffset)20 void BaseParser::Parse(const BytecodeInfoCollector &collector, const PGOTypeRecorder &typeRecorder,
21 const PGOHClassGenerator &generator, uint32_t methodOffset)
22 {
23 const JSPandaFile *jsPandaFile = collector.GetJSPandaFile();
24 const PGOBCInfo *bcInfo = collector.GetPGOBCInfo();
25
26 bcInfo->IterateInfoByType(methodOffset, type_,
27 [this, jsPandaFile, &typeRecorder, &generator, methodOffset](
28 const uint32_t bcIdx, const uint32_t bcOffset, const uint32_t) {
29 auto defType = typeRecorder.GetPGODefOpType(bcOffset);
30 if (defType.IsNone()) {
31 return;
32 }
33
34 PGOTypeLocation loc(jsPandaFile, methodOffset, bcIdx);
35 if (!RecordTypeInfo(defType, loc)) {
36 return;
37 }
38
39 GenerateHClass(generator, loc);
40 });
41 }
42
RecordTypeInfo(const PGODefineOpType & defType,const PGOTypeLocation & loc)43 bool ClassParser::RecordTypeInfo(const PGODefineOpType &defType, const PGOTypeLocation &loc)
44 {
45 auto rootType = defType.GetProfileType();
46 auto ctorPt = defType.GetCtorPt();
47 if (ctorPt.IsNone()) {
48 return false;
49 }
50 PGOSampleType ctorSampleType(ctorPt);
51
52 auto protoPt = defType.GetPrototypePt();
53 if (protoPt.IsNone()) {
54 return false;
55 }
56 PGOSampleType protoSampleType(protoPt);
57
58 ptManager_->RecordLocationToRootType(loc, rootType);
59 auto ctorLoc = loc.ChangeType(PGOTypeLocation::Type::CONSTRUCTOR);
60 ptManager_->RecordLocationToRootType(ctorLoc, ctorPt);
61
62 auto protoLoc = loc.ChangeType(PGOTypeLocation::Type::PROTOTYPE);
63 ptManager_->RecordLocationToRootType(protoLoc, protoPt);
64 return true;
65 }
66
GenerateHClass(const PGOHClassGenerator & generator,const PGOTypeLocation & loc)67 void ClassParser::GenerateHClass(const PGOHClassGenerator &generator, const PGOTypeLocation &loc)
68 {
69 auto thread = ptManager_->GetJSThread();
70 [[maybe_unused]] EcmaHandleScope scope(thread);
71
72 auto rootType = ptManager_->GetRootIdByLocation(loc);
73 PGOSampleType iSampleType(rootType);
74
75 auto ctorLoc = loc.ChangeType(PGOTypeLocation::Type::CONSTRUCTOR);
76 auto ctorPt = ptManager_->GetRootIdByLocation(ctorLoc);
77 PGOSampleType ctorSampleType(ctorPt);
78
79 auto protoLoc = loc.ChangeType(PGOTypeLocation::Type::PROTOTYPE);
80 auto protoPt = ptManager_->GetRootIdByLocation(protoLoc);
81 PGOSampleType protoSampleType(protoPt);
82
83 // testcase: propertyaccessor2.ts. protoSampleType not find desc
84 if (generator.FindHClassLayoutDesc(ctorSampleType) && generator.FindHClassLayoutDesc(protoSampleType)) {
85 generator.GenerateHClass(ctorSampleType);
86 generator.GenerateHClass(protoSampleType);
87
88 auto phValue = ptManager_->QueryHClass(protoPt, protoPt);
89 JSHandle<JSHClass> phclass(thread, phValue);
90 JSHandle<JSObject> prototype = thread->GetEcmaVM()->GetFactory()->NewJSObjectWithInit(phclass);
91 generator.GenerateIHClass(iSampleType, JSHandle<JSTaggedValue>::Cast(prototype));
92 }
93 }
94
RecordTypeInfo(const PGODefineOpType & defType,const PGOTypeLocation & loc)95 bool ArrayParser::RecordTypeInfo(const PGODefineOpType &defType, const PGOTypeLocation &loc)
96 {
97 auto rootType = defType.GetProfileType();
98 if (!rootType.IsArrayLiteralType()) {
99 return false;
100 }
101
102 ElementsKind kind = defType.GetElementsKind();
103 ptManager_->RecordLocationToElementsKind(loc, kind);
104
105 auto traceId = rootType.GetId();
106 // For PGO, we do not care whether an array isPrototype or not.
107 // This type is used at define point, we can use initial array hclass without IsPrototype bit set.
108 auto hclassIdx = ptManager_->GetJSThread()->GetArrayInstanceHClassIndex(kind, false);
109 ptManager_->RecordConstantIndex(traceId, static_cast<uint32_t>(hclassIdx));
110 return true;
111 }
112
RecordTypeInfo(const PGODefineOpType & defType,const PGOTypeLocation & loc)113 bool ObjectLiteralParser::RecordTypeInfo(const PGODefineOpType &defType, const PGOTypeLocation &loc)
114 {
115 auto rootType = defType.GetProfileType();
116 ptManager_->RecordLocationToRootType(loc, rootType);
117 return true;
118 }
119
GenerateHClass(const PGOHClassGenerator & generator,const PGOTypeLocation & loc)120 void ObjectLiteralParser::GenerateHClass(const PGOHClassGenerator &generator, const PGOTypeLocation &loc)
121 {
122 auto thread = ptManager_->GetJSThread();
123 [[maybe_unused]] EcmaHandleScope scope(thread);
124
125 auto rootType = ptManager_->GetRootIdByLocation(loc);
126 PGOSampleType rootSampleType(rootType);
127 if (!generator.IsPreprocessObjectLiteralLength()) {
128 generator.SetStatus(PGOHClassGenerator::Status::ISCACHE);
129 }
130 generator.GenerateHClass(rootSampleType);
131 }
132
RecordTypeInfo(const PGODefineOpType & defType,const PGOTypeLocation & loc)133 bool FunctionParser::RecordTypeInfo(const PGODefineOpType &defType, const PGOTypeLocation &loc)
134 {
135 auto rootType = defType.GetProfileType();
136 auto ctorPt = defType.GetCtorPt();
137 if (ctorPt.IsNone()) {
138 return false;
139 }
140 PGOSampleType ctorSampleType(ctorPt);
141
142 auto protoPt = defType.GetPrototypePt();
143 if (protoPt.IsNone()) {
144 return false;
145 }
146 PGOSampleType protoSampleType(protoPt);
147
148 ptManager_->RecordLocationToRootType(loc, rootType);
149 auto ctorLoc = loc.ChangeType(PGOTypeLocation::Type::CONSTRUCTOR);
150 ptManager_->RecordLocationToRootType(ctorLoc, ctorPt);
151
152 auto protoLoc = loc.ChangeType(PGOTypeLocation::Type::PROTOTYPE);
153 ptManager_->RecordLocationToRootType(protoLoc, protoPt);
154 return true;
155 }
156
GenerateHClass(const PGOHClassGenerator & generator,const PGOTypeLocation & loc)157 void FunctionParser::GenerateHClass(const PGOHClassGenerator &generator, const PGOTypeLocation &loc)
158 {
159 auto thread = ptManager_->GetJSThread();
160 [[maybe_unused]] EcmaHandleScope scope(thread);
161
162 auto rootType = ptManager_->GetRootIdByLocation(loc);
163 PGOSampleType iSampleType(rootType);
164
165 auto ctorLoc = loc.ChangeType(PGOTypeLocation::Type::CONSTRUCTOR);
166 auto ctorPt = ptManager_->GetRootIdByLocation(ctorLoc);
167 PGOSampleType ctorSampleType(ctorPt);
168
169 auto protoLoc = loc.ChangeType(PGOTypeLocation::Type::PROTOTYPE);
170 auto protoPt = ptManager_->GetRootIdByLocation(protoLoc);
171 PGOSampleType protoSampleType(protoPt);
172
173 // testcase: propertyaccessor2.ts. protoSampleType not find desc
174 if (generator.FindHClassLayoutDesc(ctorSampleType) && generator.FindHClassLayoutDesc(protoSampleType)) {
175 generator.GenerateHClass(protoSampleType);
176
177 auto phValue = ptManager_->QueryHClass(protoPt, protoPt);
178 JSHandle<JSHClass> phclass(thread, phValue);
179 JSHandle<JSObject> prototype = thread->GetEcmaVM()->GetFactory()->NewJSObjectWithInit(phclass);
180 generator.GenerateIHClass(iSampleType, JSHandle<JSTaggedValue>::Cast(prototype));
181 }
182 }
183
PGOTypeParser(const PGOProfilerDecoder & decoder,PGOTypeManager * ptManager)184 PGOTypeParser::PGOTypeParser(const PGOProfilerDecoder &decoder, PGOTypeManager *ptManager)
185 : decoder_(decoder), ptManager_(ptManager)
186 {
187 parsers_.emplace_back(std::make_unique<EmptyArrayParser>(ptManager));
188 parsers_.emplace_back(std::make_unique<ArrayLiteralParser>(ptManager));
189 parsers_.emplace_back(std::make_unique<ObjectLiteralParser>(ptManager));
190 }
191
SkipGenerateHClass(PGOTypeRecorder typeRecorder,ProfileType rootType,bool isCache,PGOHClassTreeDesc * desc)192 bool PGOTypeParser::SkipGenerateHClass(PGOTypeRecorder typeRecorder, ProfileType rootType,
193 bool isCache, PGOHClassTreeDesc *desc)
194 {
195 // If the definition point is not includes in the AOT list. This hclass needs to be discarded.
196 // otherwise, the using point must to be deopt.
197 if ((!rootType.IsNapiType() && !isCache && !typeRecorder.IsValidPt(rootType)) ||
198 desc->CheckHasInvalidType()) {
199 return true;
200 }
201 return false;
202 }
203
Preproccessor(BytecodeInfoCollector & collector)204 void PGOTypeParser::Preproccessor(BytecodeInfoCollector &collector)
205 {
206 const JSPandaFile *jsPandaFile = collector.GetJSPandaFile();
207 PGOTypeRecorder typeRecorder(decoder_);
208 typeRecorder.IterateProtoTransitionPool([this](PGOProtoTransitionType type) {
209 ProfileType ihcType = type.GetIhcType();
210 std::pair<ProfileType, ProfileType> baseType = type.GetBaseType();
211 ProfileType transIhcType = type.GetTransitionType();
212 ProfileType transPhcType = type.GetTransitionProtoPt();
213 ProtoTransType transType(ihcType, baseType.first, baseType.second, transIhcType, transPhcType);
214 ptManager_->RecordProtoTransType(transType);
215 });
216
217 PGOHClassGenerator::Status status = PGOHClassGenerator::Status::PREPROCESSOR;
218 typeRecorder.IterateHClassTreeDesc([this, &typeRecorder, status](PGOHClassTreeDesc *desc) {
219 auto rootType = desc->GetProfileType();
220 auto protoPt = desc->GetProtoPt();
221 bool isCache = rootType.IsObjectLiteralType();
222 if (!isCache || SkipGenerateHClass(typeRecorder, rootType, isCache, desc)) {
223 return;
224 }
225 const PGOHClassGenerator generator(typeRecorder, ptManager_, status);
226 if (rootType.IsNapiType() || rootType.IsGeneralizedPrototype() || rootType.IsConstructor()) {
227 return;
228 } else if (rootType.IsGeneralizedClassType()) {
229 generator.GenerateHClass(PGOSampleType(protoPt));
230 } else {
231 generator.GenerateHClass(PGOSampleType(rootType));
232 }
233 });
234
235 collector.IterateAllMethods([this, jsPandaFile, &collector, status](uint32_t methodOffset) {
236 PGOTypeRecorder typeRecorder(decoder_, jsPandaFile, methodOffset);
237 const PGOHClassGenerator generator(typeRecorder, ptManager_, status);
238 ObjectLiteralParser parser(ptManager_);
239 parser.Parse(collector, typeRecorder, generator, methodOffset);
240 });
241 }
242
CreatePGOType(BytecodeInfoCollector & collector)243 void PGOTypeParser::CreatePGOType(BytecodeInfoCollector &collector)
244 {
245 const JSPandaFile *jsPandaFile = collector.GetJSPandaFile();
246 PGOTypeRecorder typeRecorder(decoder_);
247 typeRecorder.IterateHClassTreeDesc([this, typeRecorder](PGOHClassTreeDesc *desc) {
248 auto rootType = desc->GetProfileType();
249 auto protoPt = desc->GetProtoPt();
250 bool isCache = rootType.IsObjectLiteralType();
251 if (SkipGenerateHClass(typeRecorder, rootType, isCache, desc)) {
252 return ;
253 }
254 PGOHClassGenerator::Status status = PGOHClassGenerator::Status::NONE;
255 if (isCache) {
256 status = PGOHClassGenerator::Status::ISCACHE;
257 }
258 const PGOHClassGenerator generator(typeRecorder, ptManager_, status);
259 if (rootType.IsNapiType()) {
260 this->GenerateHClassForNapiType(rootType, generator);
261 } else if (rootType.IsGeneralizedClassType()) {
262 this->GenerateHClassForClassType(rootType, protoPt, generator);
263 } else if (rootType.IsPrototype()) {
264 this->GenerateHClassForPrototype(rootType, generator);
265 } else {
266 generator.GenerateHClass(PGOSampleType(rootType));
267 }
268 });
269
270 collector.IterateAllMethods([this, jsPandaFile, &collector](uint32_t methodOffset) {
271 PGOTypeRecorder typeRecorder(decoder_, jsPandaFile, methodOffset);
272 const PGOHClassGenerator generator(typeRecorder, ptManager_);
273 for (auto &parser : parsers_) {
274 parser->Parse(collector, typeRecorder, generator, methodOffset);
275 }
276 });
277 }
278
GenerateHClassForNapiType(ProfileType rootType,const PGOHClassGenerator & generator)279 void PGOTypeParser::GenerateHClassForNapiType(ProfileType rootType, const PGOHClassGenerator &generator)
280 {
281 auto thread = ptManager_->GetJSThread();
282 JSHandle<JSTaggedValue> nullhandle(thread, JSTaggedValue::Null());
283 PGOSampleType rootSampleType(rootType);
284 generator.GenerateIHClass(rootSampleType, nullhandle);
285 }
286
GenerateHClassForClassType(ProfileType rootType,ProfileType protoPt,const PGOHClassGenerator & generator)287 void PGOTypeParser::GenerateHClassForClassType(ProfileType rootType, ProfileType protoPt,
288 const PGOHClassGenerator &generator)
289 {
290 if (!protoPt.IsGeneralizedPrototype()) {
291 return;
292 }
293 auto phValue = ptManager_->QueryHClass(protoPt, protoPt);
294 if (phValue.IsUndefined()) {
295 generator.GenerateHClass(PGOSampleType(protoPt));
296 }
297 phValue = ptManager_->QueryHClass(protoPt, protoPt);
298 if (phValue.IsUndefined()) {
299 return;
300 }
301 ASSERT(phValue.IsJSHClass());
302 auto thread = ptManager_->GetJSThread();
303 JSHandle<JSHClass> phclass(thread, phValue);
304 JSHandle<JSObject> prototype = thread->GetEcmaVM()->GetFactory()->NewJSObjectWithInit(phclass);
305 PGOSampleType rootSampleType(rootType);
306 generator.GenerateIHClass(rootSampleType, JSHandle<JSTaggedValue>::Cast(prototype));
307 }
308
GenerateHClassForPrototype(ProfileType rootType,const PGOHClassGenerator & generator)309 void PGOTypeParser::GenerateHClassForPrototype(ProfileType rootType, const PGOHClassGenerator &generator)
310 {
311 PGOSampleType rootSampleType(rootType);
312 // When the collected object only has phc, use phc to create a prototype and store it in the IHC field.
313 generator.GenerateHClass(rootSampleType);
314 auto classType = ProfileType(rootType.GetRaw());
315 classType.UpdateKind(ProfileType::Kind::ClassId);
316 auto ihc = ptManager_->QueryHClass(classType, classType);
317 if (ihc.IsUndefined()) {
318 auto phc = ptManager_->QueryHClass(rootType, rootType);
319 auto thread = ptManager_->GetJSThread();
320 JSHandle<JSHClass> phclass(thread, phc);
321 if (!phc.IsUndefined()) {
322 JSHandle<JSObject> prototype = thread->GetEcmaVM()->GetFactory()->NewJSObjectWithInit(phclass);
323 ptManager_->RecordHClass(classType, classType, prototype.GetTaggedType());
324 }
325 }
326 }
327 } // namespace panda::ecmascript
328