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