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 #include "ecmascript/js_hclass-inl.h"
18
19 namespace panda::ecmascript::kungfu {
FindHClassLayoutDesc(PGOSampleType type) const20 bool PGOHClassGenerator::FindHClassLayoutDesc(PGOSampleType type) const
21 {
22 PGOHClassTreeDesc *desc;
23 typeRecorder_.GetHClassTreeDesc(type, &desc);
24 if (desc == nullptr) {
25 return false;
26 }
27 if (desc->GetHClassLayoutDesc(type.GetProfileType()) == nullptr) {
28 return false;
29 }
30 return true;
31 }
32
GenerateHClass(PGOSampleType type,bool isCache) const33 bool PGOHClassGenerator::GenerateHClass(PGOSampleType type, bool isCache) const
34 {
35 auto thread = ptManager_->GetJSThread();
36 JSHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
37 PGOHClassTreeDesc *desc;
38 if (!typeRecorder_.GetHClassTreeDesc(type, &desc)) {
39 return false;
40 }
41 auto rootType = type.GetProfileType();
42 auto rootHClassDesc = desc->GetHClassLayoutDesc(rootType);
43 if (rootHClassDesc == nullptr) {
44 return false;
45 }
46
47 uint32_t rootNumOfProps = reinterpret_cast<RootHClassLayoutDesc *>(rootHClassDesc)->NumOfProps();
48 uint32_t maxNumOfProps = rootNumOfProps;
49 CaculateMaxNumOfObj(desc, rootHClassDesc, rootNumOfProps, maxNumOfProps);
50 CaculateMaxNumOfObjIncludeProtoTransition(type, maxNumOfProps);
51 if (!CheckIsValid(type, maxNumOfProps, isCache)) {
52 return false;
53 }
54
55 JSHandle<JSHClass> rootHClass;
56 if (rootType.IsGeneralizedPrototype()) {
57 rootHClass = CreateRootPHClass(rootType, rootHClassDesc, maxNumOfProps, rootType.IsTransitionPrototype());
58 } else if (rootType.IsConstructor()) {
59 rootHClass = CreateRootCHClass(rootType, rootHClassDesc, maxNumOfProps);
60 } else {
61 rootHClass = CreateRootHClass(rootType, rootHClassDesc, maxNumOfProps, isCache);
62 }
63
64 CreateChildHClass(rootType, desc, rootHClass, rootHClassDesc);
65 return true;
66 }
67
GenerateIHClass(PGOSampleType type,const JSHandle<JSObject> & prototype) const68 bool PGOHClassGenerator::GenerateIHClass(PGOSampleType type, const JSHandle<JSObject> &prototype) const
69 {
70 PGOHClassTreeDesc *desc;
71 if (!typeRecorder_.GetHClassTreeDesc(type, &desc)) {
72 return false;
73 }
74 auto rootType = type.GetProfileType();
75 auto rootHClassDesc = desc->GetHClassLayoutDesc(rootType);
76 if (rootHClassDesc == nullptr) {
77 ptManager_->RecordHClass(rootType, rootType, prototype.GetTaggedType());
78 return false;
79 }
80
81 uint32_t rootNumOfProps = reinterpret_cast<RootHClassLayoutDesc *>(rootHClassDesc)->NumOfProps();
82 uint32_t maxNumOfProps = rootNumOfProps;
83 CaculateMaxNumOfObj(desc, rootHClassDesc, rootNumOfProps, maxNumOfProps);
84 CaculateMaxNumOfObjIncludeProtoTransition(type, maxNumOfProps);
85 if (maxNumOfProps > PropertyAttributes::MAX_FAST_PROPS_CAPACITY) {
86 return false;
87 }
88
89 JSHandle<JSHClass> rootHClass = CreateRootHClass(rootType, rootHClassDesc, maxNumOfProps, false);
90 auto thread = ptManager_->GetJSThread();
91 rootHClass->SetProto(thread, prototype);
92
93 CreateChildHClass(rootType, desc, rootHClass, rootHClassDesc);
94 return true;
95 }
96
CaculateMaxNumOfObjIncludeProtoTransition(PGOSampleType type,uint32_t & maxNum) const97 void PGOHClassGenerator::CaculateMaxNumOfObjIncludeProtoTransition(PGOSampleType type, uint32_t &maxNum) const
98 {
99 auto rootType = type.GetProfileType();
100 std::vector<ProfileType> transPhcs = ptManager_->FindAllTransPhcByBaseType(rootType);
101 for (auto &transPhc : transPhcs) {
102 PGOSampleType transType(transPhc);
103 PGOHClassTreeDesc *desc;
104 if (!typeRecorder_.GetHClassTreeDesc(transType, &desc)) {
105 continue;
106 }
107 auto rootHClassDesc = desc->GetHClassLayoutDesc(transPhc);
108 if (rootHClassDesc == nullptr) {
109 continue;
110 }
111 uint32_t rootNumOfProps = reinterpret_cast<RootHClassLayoutDesc *>(rootHClassDesc)->NumOfProps();
112 uint32_t maxNumOfProps = rootNumOfProps;
113 CaculateMaxNumOfObj(desc, rootHClassDesc, rootNumOfProps, maxNumOfProps);
114 maxNum = std::max(maxNum, maxNumOfProps);
115 }
116 }
117
CaculateMaxNumOfObj(const PGOHClassTreeDesc * desc,const HClassLayoutDesc * parent,uint32_t lastNum,uint32_t & maxNum) const118 void PGOHClassGenerator::CaculateMaxNumOfObj(
119 const PGOHClassTreeDesc *desc, const HClassLayoutDesc *parent, uint32_t lastNum, uint32_t &maxNum) const
120 {
121 if (lastNum > maxNum) {
122 maxNum = lastNum;
123 }
124 parent->IterateChilds([this, desc, lastNum, &maxNum] (const ProfileType &childType) -> bool {
125 auto layoutDesc = desc->GetHClassLayoutDesc(childType);
126 if (layoutDesc == nullptr) {
127 return true;
128 }
129 CaculateMaxNumOfObj(desc, layoutDesc, lastNum + 1, maxNum);
130 return true;
131 });
132 }
133
CheckIsValid(PGOSampleType type,uint32_t maxNum,bool isCache) const134 bool PGOHClassGenerator::CheckIsValid(PGOSampleType type, uint32_t maxNum, bool isCache) const
135 {
136 if (maxNum > PropertyAttributes::MAX_FAST_PROPS_CAPACITY) {
137 return false;
138 }
139 if (isCache && !ObjectFactory::CanObjectLiteralHClassCache(maxNum)) {
140 return typeRecorder_.IsValidPt(type.GetProfileType());
141 }
142 return true;
143 }
144
CreateRootPHClass(ProfileType rootType,const HClassLayoutDesc * layoutDesc,uint32_t maxNum,bool isTransitionPhc) const145 JSHandle<JSHClass> PGOHClassGenerator::CreateRootPHClass(
146 ProfileType rootType, const HClassLayoutDesc *layoutDesc, uint32_t maxNum, bool isTransitionPhc) const
147 {
148 JSHandle<JSHClass> rootHClass = CreateRootHClass(rootType, layoutDesc, maxNum, false);
149 // transition phc is for common function now
150 if (!isTransitionPhc) {
151 rootHClass->SetClassPrototype(true);
152 }
153 rootHClass->SetIsPrototype(true);
154 return rootHClass;
155 }
156
CreateRootCHClass(ProfileType rootType,const HClassLayoutDesc * layoutDesc,uint32_t maxNum) const157 JSHandle<JSHClass> PGOHClassGenerator::CreateRootCHClass(
158 ProfileType rootType, const HClassLayoutDesc *layoutDesc, uint32_t maxNum) const
159 {
160 JSHandle<JSHClass> rootHClass = CreateRootHClass(rootType, layoutDesc, maxNum, false);
161 rootHClass->SetClassConstructor(true);
162 rootHClass->SetConstructor(true);
163 rootHClass->SetCallable(true);
164 return rootHClass;
165 }
166
CreateRootHClass(ProfileType rootType,const HClassLayoutDesc * layoutDesc,uint32_t maxNum,bool isCache) const167 JSHandle<JSHClass> PGOHClassGenerator::CreateRootHClass(
168 ProfileType rootType, const HClassLayoutDesc *layoutDesc, uint32_t maxNum, bool isCache) const
169 {
170 auto thread = ptManager_->GetJSThread();
171 auto hclassValue = ptManager_->QueryHClass(rootType, rootType);
172 JSHandle<JSHClass> rootHClass(thread, hclassValue);
173 if (hclassValue.IsUndefined()) {
174 rootHClass = JSHClass::CreateRootHClassFromPGO(thread, layoutDesc, maxNum, isCache);
175 ptManager_->RecordHClass(rootType, rootType, rootHClass.GetTaggedType());
176 }
177 return rootHClass;
178 }
179
CreateChildHClass(ProfileType rootType,const PGOHClassTreeDesc * desc,const JSHandle<JSHClass> & parent,const HClassLayoutDesc * parentLayoutDesc) const180 void PGOHClassGenerator::CreateChildHClass(ProfileType rootType, const PGOHClassTreeDesc *desc,
181 const JSHandle<JSHClass> &parent, const HClassLayoutDesc *parentLayoutDesc) const
182 {
183 parentLayoutDesc->IterateChilds([this, rootType, desc, parent] (const ProfileType &childType) -> bool {
184 auto layoutDesc = desc->GetHClassLayoutDesc(childType);
185 if (layoutDesc == nullptr) {
186 return true;
187 }
188 auto hclassValue = ptManager_->QueryHClass(rootType, childType);
189 auto thread = ptManager_->GetJSThread();
190 JSHandle<JSHClass> childHClass(thread, hclassValue);
191 if (hclassValue.IsUndefined()) {
192 childHClass = JSHClass::CreateChildHClassFromPGO(thread, parent, layoutDesc);
193 ptManager_->RecordHClass(rootType, childType, childHClass.GetTaggedType());
194 }
195 CreateChildHClass(rootType, desc, childHClass, layoutDesc);
196 return true;
197 });
198 }
199 } // namespace panda::ecmascript
200