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