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