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