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