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 19namespace panda::ecmascript::pgo { 20 21bool 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 52void PGOHClassTreeDesc::Clear() 53{ 54 IterateAll([] (HClassLayoutDesc *desc) { 55 delete desc; 56 }); 57 transitionLayout_.clear(); 58} 59 60void 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 80HClassLayoutDesc *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 89HClassLayoutDesc *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 106bool 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 124bool 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 141bool 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 150bool PGOHClassTreeDesc::IsDumped(ProfileType curType) const 151{ 152 return transitionLayout_.find(curType) != transitionLayout_.end(); 153} 154 155bool 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 174void HClassLayoutDesc::Merge(const HClassLayoutDesc *from) 175{ 176 from->IterateChilds([this] (const ProfileType &type) -> bool { 177 AddChildHClassLayoutDesc(type); 178 return true; 179 }); 180} 181 182void 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 213void 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 224void RootHClassLayoutDesc::InsertKeyAndDesc(const CString &key, const PGOHandler &handler) 225{ 226 if (!UpdateKeyAndDesc(key, handler)) { 227 layoutDesc_.emplace_back(key, handler); 228 } 229} 230 231bool 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 242void 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 252void ChildHClassLayoutDesc::InsertKeyAndDesc(const CString &key, const PGOHandler &handler) 253{ 254 if (!UpdateKeyAndDesc(key, handler)) { 255 propertyDesc_ = PropertyDesc(key, handler); 256 } 257} 258 259bool 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