• 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/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