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