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