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/pgo_profiler/pgo_profiler_layout.h"
17 #include "ecmascript/js_hclass.h"
18 #include "ecmascript/js_hclass-inl.h"
19 #include "ecmascript/js_tagged_value.h"
20
21 namespace panda::ecmascript::pgo {
Clear()22 void PGOHClassTreeDesc::Clear()
23 {
24 IterateAll([] (HClassLayoutDesc *desc) {
25 delete desc;
26 });
27 transitionLayout_.clear();
28 }
29
Merge(const PGOHClassTreeDesc & from)30 void PGOHClassTreeDesc::Merge(const PGOHClassTreeDesc &from)
31 {
32 ASSERT(from.GetProfileType() == GetProfileType());
33 from.IterateAll([this] (HClassLayoutDesc *fromDesc) {
34 auto curLayoutDesc = GetHClassLayoutDesc(fromDesc->GetProfileType());
35 if (curLayoutDesc == nullptr) {
36 if (fromDesc->GetProfileType().IsRootType()) {
37 RootHClassLayoutDesc *rootFromTreeDesc = reinterpret_cast<RootHClassLayoutDesc *>(fromDesc);
38 curLayoutDesc = new RootHClassLayoutDesc(*rootFromTreeDesc);
39 } else {
40 ChildHClassLayoutDesc *childFromTreeDesc = reinterpret_cast<ChildHClassLayoutDesc *>(fromDesc);
41 curLayoutDesc = new ChildHClassLayoutDesc(*childFromTreeDesc);
42 }
43 transitionLayout_.emplace(fromDesc->GetProfileType(), curLayoutDesc);
44 } else {
45 curLayoutDesc->Merge(fromDesc);
46 }
47 });
48 }
49
GetHClassLayoutDesc(ProfileType type) const50 HClassLayoutDesc *PGOHClassTreeDesc::GetHClassLayoutDesc(ProfileType type) const
51 {
52 auto iter = transitionLayout_.find(type);
53 if (iter != transitionLayout_.end()) {
54 return iter->second;
55 }
56 return nullptr;
57 }
58
GetOrInsertHClassLayoutDesc(ProfileType type,bool root)59 HClassLayoutDesc *PGOHClassTreeDesc::GetOrInsertHClassLayoutDesc(ProfileType type, bool root)
60 {
61 auto iter = transitionLayout_.find(type);
62 if (iter != transitionLayout_.end()) {
63 return iter->second;
64 } else {
65 HClassLayoutDesc *layout;
66 if (root) {
67 layout = new RootHClassLayoutDesc(type);
68 } else {
69 layout = new ChildHClassLayoutDesc(type);
70 }
71 transitionLayout_.emplace(type, layout);
72 return layout;
73 }
74 }
75
DumpForRoot(JSTaggedType root,ProfileType rootType)76 bool PGOHClassTreeDesc::DumpForRoot(JSTaggedType root, ProfileType rootType)
77 {
78 ASSERT(rootType.IsRootType());
79 HClassLayoutDesc *rootLayout;
80 auto iter = transitionLayout_.find(rootType);
81 auto rootHClass = JSHClass::Cast(JSTaggedValue(root).GetTaggedObject());
82 if (iter != transitionLayout_.end()) {
83 rootLayout = iter->second;
84 } else {
85 rootLayout = new RootHClassLayoutDesc(rootType, rootHClass->GetObjectType(),
86 rootHClass->GetObjectSizeExcludeInlinedProps());
87 transitionLayout_.emplace(rootType, rootLayout);
88 }
89
90 return JSHClass::DumpForRootHClass(rootHClass, rootLayout);
91 }
92
DumpForChild(JSTaggedType child,ProfileType childType)93 bool PGOHClassTreeDesc::DumpForChild(JSTaggedType child, ProfileType childType)
94 {
95 ASSERT(!childType.IsRootType());
96 auto rootType = GetProfileType();
97 auto rootIter = transitionLayout_.find(rootType);
98 auto childHClass = JSHClass::Cast(JSTaggedValue(child).GetTaggedObject());
99 if (rootIter != transitionLayout_.end()) {
100 auto rootLayout = rootIter->second;
101 JSHClass::UpdateRootLayoutDesc(childHClass, this, rootLayout);
102 }
103
104 HClassLayoutDesc *childLayout;
105 auto iter = transitionLayout_.find(childType);
106 if (iter != transitionLayout_.end()) {
107 childLayout = iter->second;
108 return JSHClass::UpdateChildLayoutDesc(childHClass, childLayout);
109 } else {
110 childLayout = new ChildHClassLayoutDesc(childType);
111 transitionLayout_.emplace(childType, childLayout);
112 return JSHClass::DumpForChildHClass(childHClass, childLayout);
113 }
114 }
115
UpdateLayout(JSTaggedType curHClass,ProfileType curType)116 bool PGOHClassTreeDesc::UpdateLayout(JSTaggedType curHClass, ProfileType curType)
117 {
118 if (curType.IsRootType()) {
119 return DumpForRoot(curHClass, curType);
120 } else {
121 return DumpForChild(curHClass, curType);
122 }
123 }
124
IsDumped(ProfileType curType) const125 bool PGOHClassTreeDesc::IsDumped(ProfileType curType) const
126 {
127 return transitionLayout_.find(curType) != transitionLayout_.end();
128 }
129
UpdateForTransition(JSTaggedType parent,ProfileType parentType,JSTaggedType child,ProfileType childType)130 bool PGOHClassTreeDesc::UpdateForTransition(
131 JSTaggedType parent, ProfileType parentType, JSTaggedType child, ProfileType childType)
132 {
133 if (parentType.IsRootType()) {
134 if (!DumpForRoot(parent, parentType)) {
135 return false;
136 }
137 } else {
138 if (!DumpForChild(parent, parentType)) {
139 return false;
140 }
141 }
142 bool ret = DumpForChild(child, childType);
143 auto parentLayoutDesc = transitionLayout_.find(parentType)->second;
144 auto childLayoutDesc = transitionLayout_.find(childType)->second;
145 parentLayoutDesc->AddChildHClassLayoutDesc(childLayoutDesc->GetProfileType());
146 return ret;
147 }
148
Merge(const HClassLayoutDesc * from)149 void HClassLayoutDesc::Merge(const HClassLayoutDesc *from)
150 {
151 from->IterateChilds([this] (const ProfileType &type) -> bool {
152 AddChildHClassLayoutDesc(type);
153 return true;
154 });
155 }
156
InsertKeyAndDesc(const PGOHandler & handler,PropertyDesc & desc)157 void HClassLayoutDesc::InsertKeyAndDesc(const PGOHandler &handler, PropertyDesc &desc)
158 {
159 PGOHandler oldHandler = desc.second;
160 if (oldHandler == handler) {
161 return;
162 }
163 auto oldTrackType = oldHandler.GetTrackType();
164 auto newTrackType = handler.GetTrackType();
165 if (oldTrackType == newTrackType) {
166 desc.second.SetPropertyMeta(handler.GetPropertyMeta());
167 return;
168 }
169
170 switch (oldTrackType) {
171 case TrackType::TAGGED:
172 desc.second.SetPropertyMeta(handler.GetPropertyMeta());
173 break;
174 case TrackType::NONE:
175 case TrackType::INT:
176 case TrackType::DOUBLE:
177 if (newTrackType != TrackType::TAGGED) {
178 newTrackType = static_cast<TrackType>(static_cast<uint8_t>(newTrackType) |
179 static_cast<uint8_t>(oldTrackType));
180 }
181 desc.second = PGOHandler(newTrackType, handler.GetPropertyMeta());
182 break;
183 default:
184 break;
185 }
186 }
187
Merge(const HClassLayoutDesc * from)188 void RootHClassLayoutDesc::Merge(const HClassLayoutDesc *from)
189 {
190 ASSERT(from->GetProfileType() == GetProfileType());
191 ASSERT(from->GetProfileType().IsRootType());
192 auto fromDesc = reinterpret_cast<const RootHClassLayoutDesc *>(from);
193 fromDesc->IterateProps([this] (const PropertyDesc &desc) {
194 InsertKeyAndDesc(desc.first, desc.second);
195 });
196 HClassLayoutDesc::Merge(from);
197 }
198
InsertKeyAndDesc(const CString & key,const PGOHandler & handler)199 void RootHClassLayoutDesc::InsertKeyAndDesc(const CString &key, const PGOHandler &handler)
200 {
201 if (!UpdateKeyAndDesc(key, handler)) {
202 layoutDesc_.emplace_back(key, handler);
203 }
204 }
205
UpdateKeyAndDesc(const CString & key,const PGOHandler & handler)206 bool RootHClassLayoutDesc::UpdateKeyAndDesc(const CString &key, const PGOHandler &handler)
207 {
208 for (auto &iter : layoutDesc_) {
209 if (iter.first == key) {
210 HClassLayoutDesc::InsertKeyAndDesc(handler, iter);
211 return true;
212 }
213 }
214 return false;
215 }
216
Merge(const HClassLayoutDesc * from)217 void ChildHClassLayoutDesc::Merge(const HClassLayoutDesc *from)
218 {
219 ASSERT(from->GetProfileType() == GetProfileType());
220 ASSERT(!from->GetProfileType().IsRootType());
221 auto fromDesc = reinterpret_cast<const ChildHClassLayoutDesc *>(from);
222 auto fromPropDesc = fromDesc->GetPropertyDesc();
223 InsertKeyAndDesc(fromPropDesc.first, fromPropDesc.second);
224 HClassLayoutDesc::Merge(from);
225 }
226
InsertKeyAndDesc(const CString & key,const PGOHandler & handler)227 void ChildHClassLayoutDesc::InsertKeyAndDesc(const CString &key, const PGOHandler &handler)
228 {
229 if (!UpdateKeyAndDesc(key, handler)) {
230 propertyDesc_ = PropertyDesc(key, handler);
231 }
232 }
233
UpdateKeyAndDesc(const CString & key,const PGOHandler & handler)234 bool ChildHClassLayoutDesc::UpdateKeyAndDesc(const CString &key, const PGOHandler &handler)
235 {
236 if (propertyDesc_.first == key) {
237 HClassLayoutDesc::InsertKeyAndDesc(handler, propertyDesc_);
238 return true;
239 }
240 return false;
241 }
242 } // namespace panda::ecmascript::pgo
243