• 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_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