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_hclass_generator.h"
17
18 namespace panda::ecmascript::kungfu {
IsCache() const19 bool PGOHClassGenerator::IsCache() const
20 {
21 return status_ == Status::ISCACHE;
22 }
23
IsPreprocessObjectLiteralLength() const24 bool PGOHClassGenerator::IsPreprocessObjectLiteralLength() const
25 {
26 return status_ == Status::PREPROCESSOR;
27 }
28
SetStatus(Status status) const29 void PGOHClassGenerator::SetStatus(Status status) const
30 {
31 status_ = status;
32 }
33
FindHClassLayoutDesc(PGOSampleType type) const34 bool PGOHClassGenerator::FindHClassLayoutDesc(PGOSampleType type) const
35 {
36 PGOHClassTreeDesc *desc;
37 typeRecorder_.GetHClassTreeDesc(type, &desc);
38 if (desc == nullptr) {
39 return false;
40 }
41 if (desc->GetHClassLayoutDesc(type.GetProfileType()) == nullptr) {
42 return false;
43 }
44 return true;
45 }
46
GenerateHClass(PGOSampleType type) const47 bool PGOHClassGenerator::GenerateHClass(PGOSampleType type) const
48 {
49 auto thread = ptManager_->GetJSThread();
50 JSHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
51 PGOHClassTreeDesc *desc;
52 if (!typeRecorder_.GetHClassTreeDesc(type, &desc)) {
53 return false;
54 }
55
56 if (desc->CheckHasInvalidType()) {
57 return false;
58 }
59
60 auto rootType = type.GetProfileType();
61 auto rootHClassDesc = desc->GetHClassLayoutDesc(rootType);
62 if (rootHClassDesc == nullptr) {
63 return false;
64 }
65
66 uint32_t rootNumOfProps = reinterpret_cast<RootHClassLayoutDesc *>(rootHClassDesc)->NumOfProps();
67 uint32_t maxNumOfProps = rootNumOfProps;
68 CalculateMaxNumOfObj(desc, rootHClassDesc, rootNumOfProps, maxNumOfProps);
69 CalculateMaxNumOfObjIncludeProtoTransition(type, maxNumOfProps);
70 if (!CheckIsValid(type, maxNumOfProps)) {
71 return false;
72 }
73
74 if (IsPreprocessObjectLiteralLength()) {
75 if (!ObjectFactory::CanObjectLiteralHClassCache(maxNumOfProps)) {
76 return false;
77 }
78 ptManager_->SetMaxPropsNum(rootNumOfProps, maxNumOfProps);
79 JSHClass::CalculateMaxNumForChild(rootHClassDesc, maxNumOfProps);
80 } else {
81 JSHandle<JSHClass> rootHClass;
82 if (rootType.IsGeneralizedPrototype()) {
83 rootHClass = CreateRootPHClass(rootType, rootHClassDesc, maxNumOfProps, rootType.IsTransitionPrototype());
84 } else if (rootType.IsConstructor()) {
85 rootHClass = CreateRootCHClass(rootType, rootHClassDesc, maxNumOfProps);
86 } else if (IsCache() && ObjectFactory::CanObjectLiteralHClassCache(maxNumOfProps)) {
87 uint32_t maxChildNum = ptManager_->GetMaxPropsNum(rootNumOfProps);
88 ASSERT(maxChildNum >= maxNumOfProps);
89 rootHClass = CreateRootHClassWithCached(rootType, rootHClassDesc,
90 rootNumOfProps, maxChildNum);
91 } else {
92 rootHClass = CreateRootHClass(rootType, rootHClassDesc, maxNumOfProps);
93 }
94 CreateChildHClass(rootType, desc, rootHClass, rootHClassDesc);
95 }
96 return true;
97 }
98
GenerateIHClass(PGOSampleType type,const JSHandle<JSTaggedValue> & prototype) const99 bool PGOHClassGenerator::GenerateIHClass(PGOSampleType type, const JSHandle<JSTaggedValue> &prototype) const
100 {
101 PGOHClassTreeDesc *desc;
102 if (!typeRecorder_.GetHClassTreeDesc(type, &desc)) {
103 return false;
104 }
105
106 if (desc->CheckHasInvalidType()) {
107 return false;
108 }
109
110 auto rootType = type.GetProfileType();
111 auto rootHClassDesc = desc->GetHClassLayoutDesc(rootType);
112 if (rootHClassDesc == nullptr) {
113 ptManager_->RecordHClass(rootType, rootType, prototype.GetTaggedType());
114 return false;
115 }
116
117 uint32_t rootNumOfProps = reinterpret_cast<RootHClassLayoutDesc *>(rootHClassDesc)->NumOfProps();
118 uint32_t maxNumOfProps = rootNumOfProps;
119 CalculateMaxNumOfObj(desc, rootHClassDesc, rootNumOfProps, maxNumOfProps);
120 CalculateMaxNumOfObjIncludeProtoTransition(type, maxNumOfProps);
121 if (maxNumOfProps > PropertyAttributes::MAX_FAST_PROPS_CAPACITY) {
122 return false;
123 }
124
125 JSHandle<JSHClass> rootHClass = CreateRootHClass(rootType, rootHClassDesc, maxNumOfProps);
126 auto thread = ptManager_->GetJSThread();
127 rootHClass->SetProto(thread, prototype);
128
129 CreateChildHClass(rootType, desc, rootHClass, rootHClassDesc);
130 return true;
131 }
132
CalculateMaxNumOfObjIncludeProtoTransition(PGOSampleType type,uint32_t & maxNum) const133 void PGOHClassGenerator::CalculateMaxNumOfObjIncludeProtoTransition(PGOSampleType type, uint32_t &maxNum) const
134 {
135 auto rootType = type.GetProfileType();
136 std::vector<ProfileType> transPhcs = ptManager_->FindAllTransPhcByBaseType(rootType);
137 for (auto &transPhc : transPhcs) {
138 PGOSampleType transType(transPhc);
139 PGOHClassTreeDesc *desc;
140 if (!typeRecorder_.GetHClassTreeDesc(transType, &desc)) {
141 continue;
142 }
143 auto rootHClassDesc = desc->GetHClassLayoutDesc(transPhc);
144 if (rootHClassDesc == nullptr) {
145 continue;
146 }
147 uint32_t rootNumOfProps = reinterpret_cast<RootHClassLayoutDesc *>(rootHClassDesc)->NumOfProps();
148 uint32_t maxNumOfProps = rootNumOfProps;
149 CalculateMaxNumOfObj(desc, rootHClassDesc, rootNumOfProps, maxNumOfProps);
150 maxNum = std::max(maxNum, maxNumOfProps);
151 }
152 }
153
CalculateMaxNumOfObj(const PGOHClassTreeDesc * desc,const HClassLayoutDesc * parent,uint32_t lastNum,uint32_t & maxNum) const154 void PGOHClassGenerator::CalculateMaxNumOfObj(
155 const PGOHClassTreeDesc *desc, const HClassLayoutDesc *parent, uint32_t lastNum, uint32_t &maxNum) const
156 {
157 if (lastNum > maxNum) {
158 maxNum = lastNum;
159 }
160 parent->IterateChilds([this, desc, lastNum, &maxNum] (const ProfileType &childType) -> bool {
161 auto layoutDesc = desc->GetHClassLayoutDesc(childType);
162 if (layoutDesc == nullptr) {
163 return true;
164 }
165 CalculateMaxNumOfObj(desc, layoutDesc, lastNum + 1, maxNum);
166 return true;
167 });
168 }
169
CheckIsValid(PGOSampleType type,uint32_t maxNum) const170 bool PGOHClassGenerator::CheckIsValid(PGOSampleType type, uint32_t maxNum) const
171 {
172 if (maxNum > PropertyAttributes::MAX_FAST_PROPS_CAPACITY) {
173 return false;
174 }
175 if ((IsCache() || IsPreprocessObjectLiteralLength()) &&
176 !ObjectFactory::CanObjectLiteralHClassCache(maxNum)) {
177 return typeRecorder_.IsValidPt(type.GetProfileType());
178 }
179 return true;
180 }
181
CreateRootPHClass(ProfileType rootType,const HClassLayoutDesc * layoutDesc,uint32_t maxNum,bool isTransitionPhc) const182 JSHandle<JSHClass> PGOHClassGenerator::CreateRootPHClass(
183 ProfileType rootType, const HClassLayoutDesc *layoutDesc, uint32_t maxNum, bool isTransitionPhc) const
184 {
185 JSHandle<JSHClass> rootHClass = CreateRootHClass(rootType, layoutDesc, maxNum);
186 // transition phc is for common function now
187 if (!isTransitionPhc) {
188 rootHClass->SetClassPrototype(true);
189 }
190 rootHClass->SetIsPrototype(true);
191 return rootHClass;
192 }
193
CreateRootCHClass(ProfileType rootType,const HClassLayoutDesc * layoutDesc,uint32_t maxNum) const194 JSHandle<JSHClass> PGOHClassGenerator::CreateRootCHClass(
195 ProfileType rootType, const HClassLayoutDesc *layoutDesc, uint32_t maxNum) const
196 {
197 JSHandle<JSHClass> rootHClass = CreateRootHClass(rootType, layoutDesc, maxNum);
198 rootHClass->SetClassConstructor(true);
199 rootHClass->SetConstructor(true);
200 rootHClass->SetCallable(true);
201 return rootHClass;
202 }
203
CreateRootHClass(ProfileType rootType,const HClassLayoutDesc * layoutDesc,uint32_t maxNum) const204 JSHandle<JSHClass> PGOHClassGenerator::CreateRootHClass(
205 ProfileType rootType, const HClassLayoutDesc *layoutDesc, uint32_t maxNum) const
206 {
207 auto thread = ptManager_->GetJSThread();
208 auto hclassValue = ptManager_->QueryHClass(rootType, rootType);
209 JSHandle<JSHClass> rootHClass(thread, hclassValue);
210 if (hclassValue.IsUndefined()) {
211 rootHClass = JSHClass::CreateRootHClassFromPGO(thread, layoutDesc, maxNum);
212 ptManager_->RecordHClass(rootType, rootType, rootHClass.GetTaggedType());
213 }
214 return rootHClass;
215 }
216
CreateRootHClassWithCached(ProfileType rootType,const HClassLayoutDesc * layoutDesc,uint32_t literalLength,uint32_t maxPropsNum) const217 JSHandle<JSHClass> PGOHClassGenerator::CreateRootHClassWithCached(
218 ProfileType rootType, const HClassLayoutDesc *layoutDesc,
219 uint32_t literalLength, uint32_t maxPropsNum) const
220 {
221 auto thread = ptManager_->GetJSThread();
222 auto hclassValue = ptManager_->QueryHClass(rootType, rootType);
223 JSHandle<JSHClass> rootHClass(thread, hclassValue);
224 if (hclassValue.IsUndefined()) {
225 rootHClass = JSHClass::CreateRootHClassWithCached(thread, layoutDesc, literalLength, maxPropsNum);
226 ptManager_->RecordHClass(rootType, rootType, rootHClass.GetTaggedType());
227 }
228 return rootHClass;
229 }
230
CreateChildHClass(ProfileType rootType,const PGOHClassTreeDesc * desc,const JSHandle<JSHClass> & parent,const HClassLayoutDesc * parentLayoutDesc) const231 void PGOHClassGenerator::CreateChildHClass(ProfileType rootType, const PGOHClassTreeDesc *desc,
232 const JSHandle<JSHClass> &parent, const HClassLayoutDesc *parentLayoutDesc) const
233 {
234 parentLayoutDesc->IterateChilds([this, rootType, desc, parent] (const ProfileType &childType) -> bool {
235 auto layoutDesc = desc->GetHClassLayoutDesc(childType);
236 if (layoutDesc == nullptr) {
237 return true;
238 }
239 auto hclassValue = ptManager_->QueryHClass(rootType, childType);
240 auto thread = ptManager_->GetJSThread();
241 JSHandle<JSHClass> childHClass(thread, hclassValue);
242 if (hclassValue.IsUndefined()) {
243 childHClass = JSHClass::CreateChildHClassFromPGO(thread, parent, layoutDesc);
244 ptManager_->RecordHClass(rootType, childType, childHClass.GetTaggedType());
245 }
246 CreateChildHClass(rootType, desc, childHClass, layoutDesc);
247 return true;
248 });
249 }
250 } // namespace panda::ecmascript
251