• 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     generator.SetStatus(PGOHClassGenerator::Status::ISCACHE);
128     generator.GenerateHClass(rootSampleType);
129 }
130 
RecordTypeInfo(const PGODefineOpType & defType,const PGOTypeLocation & loc)131 bool FunctionParser::RecordTypeInfo(const PGODefineOpType &defType, const PGOTypeLocation &loc)
132 {
133     auto rootType = defType.GetProfileType();
134     auto ctorPt = defType.GetCtorPt();
135     if (ctorPt.IsNone()) {
136         return false;
137     }
138     PGOSampleType ctorSampleType(ctorPt);
139 
140     auto protoPt = defType.GetPrototypePt();
141     if (protoPt.IsNone()) {
142         return false;
143     }
144     PGOSampleType protoSampleType(protoPt);
145 
146     ptManager_->RecordLocationToRootType(loc, rootType);
147     auto ctorLoc = loc.ChangeType(PGOTypeLocation::Type::CONSTRUCTOR);
148     ptManager_->RecordLocationToRootType(ctorLoc, ctorPt);
149 
150     auto protoLoc = loc.ChangeType(PGOTypeLocation::Type::PROTOTYPE);
151     ptManager_->RecordLocationToRootType(protoLoc, protoPt);
152     return true;
153 }
154 
GenerateHClass(const PGOHClassGenerator & generator,const PGOTypeLocation & loc)155 void FunctionParser::GenerateHClass(const PGOHClassGenerator &generator, const PGOTypeLocation &loc)
156 {
157     auto thread = ptManager_->GetJSThread();
158     [[maybe_unused]] EcmaHandleScope scope(thread);
159 
160     auto rootType = ptManager_->GetRootIdByLocation(loc);
161     PGOSampleType iSampleType(rootType);
162 
163     auto ctorLoc = loc.ChangeType(PGOTypeLocation::Type::CONSTRUCTOR);
164     auto ctorPt = ptManager_->GetRootIdByLocation(ctorLoc);
165     PGOSampleType ctorSampleType(ctorPt);
166 
167     auto protoLoc = loc.ChangeType(PGOTypeLocation::Type::PROTOTYPE);
168     auto protoPt = ptManager_->GetRootIdByLocation(protoLoc);
169     PGOSampleType protoSampleType(protoPt);
170 
171     // testcase: propertyaccessor2.ts. protoSampleType not find desc
172     if (generator.FindHClassLayoutDesc(ctorSampleType) && generator.FindHClassLayoutDesc(protoSampleType)) {
173         generator.GenerateHClass(protoSampleType);
174 
175         auto phValue = ptManager_->QueryHClass(protoPt, protoPt);
176         JSHandle<JSHClass> phclass(thread, phValue);
177         JSHandle<JSObject> prototype = thread->GetEcmaVM()->GetFactory()->NewJSObjectWithInit(phclass);
178         generator.GenerateIHClass(iSampleType, JSHandle<JSTaggedValue>::Cast(prototype));
179     }
180 }
181 
PGOTypeParser(const PGOProfilerDecoder & decoder,PGOTypeManager * ptManager)182 PGOTypeParser::PGOTypeParser(const PGOProfilerDecoder &decoder, PGOTypeManager *ptManager)
183     : decoder_(decoder), ptManager_(ptManager)
184 {
185     parsers_.emplace_back(std::make_unique<EmptyArrayParser>(ptManager));
186     parsers_.emplace_back(std::make_unique<ArrayLiteralParser>(ptManager));
187     parsers_.emplace_back(std::make_unique<ObjectLiteralParser>(ptManager));
188 }
189 
SkipGenerateHClass(PGOTypeRecorder typeRecorder,ProfileType rootType,bool isCache,PGOHClassTreeDesc * desc)190 bool PGOTypeParser::SkipGenerateHClass(PGOTypeRecorder typeRecorder, ProfileType rootType,
191                                        bool isCache, PGOHClassTreeDesc *desc)
192 {
193     // If the definition point is not includes in the AOT list. This hclass needs to be discarded.
194     // otherwise, the using point must to be deopt.
195     if ((!rootType.IsNapiType() && !isCache && !typeRecorder.IsValidPt(rootType)) ||
196          desc->CheckHasInvalidType()) {
197         return true;
198     }
199     return false;
200 }
201 
CreatePGOType(BytecodeInfoCollector & collector)202 void PGOTypeParser::CreatePGOType(BytecodeInfoCollector &collector)
203 {
204     const JSPandaFile *jsPandaFile = collector.GetJSPandaFile();
205     PGOTypeRecorder typeRecorder(decoder_);
206     typeRecorder.IterateProtoTransitionPool([this](PGOProtoTransitionType type) {
207         ProfileType ihcType = type.GetIhcType();
208         std::pair<ProfileType, ProfileType> baseType = type.GetBaseType();
209         ProfileType transIhcType = type.GetTransitionType();
210         ProfileType transPhcType = type.GetTransitionProtoPt();
211         ProtoTransType transType(ihcType, baseType.first, baseType.second, transIhcType, transPhcType);
212         ptManager_->RecordProtoTransType(transType);
213     });
214 
215     typeRecorder.IterateHClassTreeDesc([this, typeRecorder](PGOHClassTreeDesc *desc) {
216         auto rootType = desc->GetProfileType();
217         auto protoPt = desc->GetProtoPt();
218         bool isCache = rootType.IsObjectLiteralType();
219         if (SkipGenerateHClass(typeRecorder, rootType, isCache, desc)) {
220             return ;
221         }
222         PGOHClassGenerator::Status status = PGOHClassGenerator::Status::NONE;
223         if (isCache) {
224             status = PGOHClassGenerator::Status::ISCACHE;
225         }
226         const PGOHClassGenerator generator(typeRecorder, ptManager_, status);
227         if (rootType.IsNapiType()) {
228             this->GenerateHClassForNapiType(rootType, generator);
229         } else if (rootType.IsGeneralizedClassType()) {
230             this->GenerateHClassForClassType(rootType, protoPt, generator);
231         } else if (rootType.IsPrototype()) {
232             this->GenerateHClassForPrototype(rootType, generator);
233         } else {
234             generator.GenerateHClass(PGOSampleType(rootType));
235         }
236     });
237 
238     collector.IterateAllMethods([this, jsPandaFile, &collector](uint32_t methodOffset) {
239         PGOTypeRecorder typeRecorder(decoder_, jsPandaFile, methodOffset);
240         const PGOHClassGenerator generator(typeRecorder, ptManager_);
241         for (auto &parser : parsers_) {
242             parser->Parse(collector, typeRecorder, generator, methodOffset);
243         }
244     });
245 }
246 
GenerateHClassForNapiType(ProfileType rootType,const PGOHClassGenerator & generator)247 void PGOTypeParser::GenerateHClassForNapiType(ProfileType rootType, const PGOHClassGenerator &generator)
248 {
249     auto thread = ptManager_->GetJSThread();
250     JSHandle<JSTaggedValue> nullhandle(thread, JSTaggedValue::Null());
251     PGOSampleType rootSampleType(rootType);
252     generator.GenerateIHClass(rootSampleType, nullhandle);
253 }
254 
GenerateHClassForClassType(ProfileType rootType,ProfileType protoPt,const PGOHClassGenerator & generator)255 void PGOTypeParser::GenerateHClassForClassType(ProfileType rootType, ProfileType protoPt,
256                                                const PGOHClassGenerator &generator)
257 {
258     if (!protoPt.IsGeneralizedPrototype()) {
259         return;
260     }
261     auto phValue = ptManager_->QueryHClass(protoPt, protoPt);
262     if (phValue.IsUndefined()) {
263         generator.GenerateHClass(PGOSampleType(protoPt));
264     }
265     phValue = ptManager_->QueryHClass(protoPt, protoPt);
266     if (phValue.IsUndefined()) {
267         return;
268     }
269     ASSERT(phValue.IsJSHClass());
270     auto thread = ptManager_->GetJSThread();
271     JSHandle<JSHClass> phclass(thread, phValue);
272     JSHandle<JSObject> prototype = thread->GetEcmaVM()->GetFactory()->NewJSObjectWithInit(phclass);
273     PGOSampleType rootSampleType(rootType);
274     generator.GenerateIHClass(rootSampleType, JSHandle<JSTaggedValue>::Cast(prototype));
275 }
276 
GenerateHClassForPrototype(ProfileType rootType,const PGOHClassGenerator & generator)277 void PGOTypeParser::GenerateHClassForPrototype(ProfileType rootType, const PGOHClassGenerator &generator)
278 {
279     PGOSampleType rootSampleType(rootType);
280     // When the collected object only has phc, use phc to create a prototype and store it in the IHC field.
281     generator.GenerateHClass(rootSampleType);
282     auto classType = ProfileType(rootType.GetRaw());
283     classType.UpdateKind(ProfileType::Kind::ClassId);
284     auto ihc = ptManager_->QueryHClass(classType, classType);
285     if (ihc.IsUndefined()) {
286         auto phc = ptManager_->QueryHClass(rootType, rootType);
287         auto thread = ptManager_->GetJSThread();
288         JSHandle<JSHClass> phclass(thread, phc);
289         if (!phc.IsUndefined()) {
290             JSHandle<JSObject> prototype = thread->GetEcmaVM()->GetFactory()->NewJSObjectWithInit(phclass);
291             ptManager_->RecordHClass(classType, classType, prototype.GetTaggedType());
292         }
293     }
294 }
295 }  // namespace panda::ecmascript
296