14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/pgo_profiler/pgo_profiler_layout.h"
174514f5e3Sopenharmony_ci#include "ecmascript/js_thread.h"
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_cinamespace panda::ecmascript::pgo {
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_cibool PGOHandler::SetAttribute(const JSThread *thread, PropertyAttributes &attr) const
224514f5e3Sopenharmony_ci{
234514f5e3Sopenharmony_ci    bool ret = false;
244514f5e3Sopenharmony_ci    if (thread->GetEcmaVM()->GetJSOptions().IsEnableOptTrackField()) {
254514f5e3Sopenharmony_ci        TrackType trackType = GetTrackType();
264514f5e3Sopenharmony_ci        attr.SetTrackType(trackType);
274514f5e3Sopenharmony_ci        switch (trackType) {
284514f5e3Sopenharmony_ci            case TrackType::DOUBLE:
294514f5e3Sopenharmony_ci            case TrackType::NUMBER:
304514f5e3Sopenharmony_ci                attr.SetRepresentation(Representation::DOUBLE);
314514f5e3Sopenharmony_ci                ret = true;
324514f5e3Sopenharmony_ci                break;
334514f5e3Sopenharmony_ci            case TrackType::INT:
344514f5e3Sopenharmony_ci                attr.SetRepresentation(Representation::INT);
354514f5e3Sopenharmony_ci                ret = true;
364514f5e3Sopenharmony_ci                break;
374514f5e3Sopenharmony_ci            case TrackType::TAGGED:
384514f5e3Sopenharmony_ci            default:
394514f5e3Sopenharmony_ci                attr.SetRepresentation(Representation::TAGGED);
404514f5e3Sopenharmony_ci                break;
414514f5e3Sopenharmony_ci        }
424514f5e3Sopenharmony_ci    } else {
434514f5e3Sopenharmony_ci        attr.SetRepresentation(Representation::TAGGED);
444514f5e3Sopenharmony_ci    }
454514f5e3Sopenharmony_ci    attr.SetWritable(IsWritable());
464514f5e3Sopenharmony_ci    attr.SetEnumerable(IsEnumerable());
474514f5e3Sopenharmony_ci    attr.SetConfigurable(IsConfigurable());
484514f5e3Sopenharmony_ci    attr.SetIsAccessor(IsAccessor());
494514f5e3Sopenharmony_ci    return ret;
504514f5e3Sopenharmony_ci}
514514f5e3Sopenharmony_ci
524514f5e3Sopenharmony_civoid PGOHClassTreeDesc::Clear()
534514f5e3Sopenharmony_ci{
544514f5e3Sopenharmony_ci    IterateAll([] (HClassLayoutDesc *desc) {
554514f5e3Sopenharmony_ci        delete desc;
564514f5e3Sopenharmony_ci    });
574514f5e3Sopenharmony_ci    transitionLayout_.clear();
584514f5e3Sopenharmony_ci}
594514f5e3Sopenharmony_ci
604514f5e3Sopenharmony_civoid PGOHClassTreeDesc::Merge(const PGOHClassTreeDesc &from)
614514f5e3Sopenharmony_ci{
624514f5e3Sopenharmony_ci    ASSERT(from.GetProfileType() == GetProfileType());
634514f5e3Sopenharmony_ci    from.IterateAll([this] (HClassLayoutDesc *fromDesc) {
644514f5e3Sopenharmony_ci        auto curLayoutDesc = GetHClassLayoutDesc(fromDesc->GetProfileType());
654514f5e3Sopenharmony_ci        if (curLayoutDesc == nullptr) {
664514f5e3Sopenharmony_ci            if (fromDesc->GetProfileType().IsRootType()) {
674514f5e3Sopenharmony_ci                RootHClassLayoutDesc *rootFromTreeDesc = reinterpret_cast<RootHClassLayoutDesc *>(fromDesc);
684514f5e3Sopenharmony_ci                curLayoutDesc = new RootHClassLayoutDesc(*rootFromTreeDesc);
694514f5e3Sopenharmony_ci            } else {
704514f5e3Sopenharmony_ci                ChildHClassLayoutDesc *childFromTreeDesc = reinterpret_cast<ChildHClassLayoutDesc *>(fromDesc);
714514f5e3Sopenharmony_ci                curLayoutDesc = new ChildHClassLayoutDesc(*childFromTreeDesc);
724514f5e3Sopenharmony_ci            }
734514f5e3Sopenharmony_ci            transitionLayout_.emplace(fromDesc->GetProfileType(), curLayoutDesc);
744514f5e3Sopenharmony_ci        } else {
754514f5e3Sopenharmony_ci            curLayoutDesc->Merge(fromDesc);
764514f5e3Sopenharmony_ci        }
774514f5e3Sopenharmony_ci    });
784514f5e3Sopenharmony_ci}
794514f5e3Sopenharmony_ci
804514f5e3Sopenharmony_ciHClassLayoutDesc *PGOHClassTreeDesc::GetHClassLayoutDesc(ProfileType type) const
814514f5e3Sopenharmony_ci{
824514f5e3Sopenharmony_ci    auto iter = transitionLayout_.find(type);
834514f5e3Sopenharmony_ci    if (iter != transitionLayout_.end()) {
844514f5e3Sopenharmony_ci        return iter->second;
854514f5e3Sopenharmony_ci    }
864514f5e3Sopenharmony_ci    return nullptr;
874514f5e3Sopenharmony_ci}
884514f5e3Sopenharmony_ci
894514f5e3Sopenharmony_ciHClassLayoutDesc *PGOHClassTreeDesc::GetOrInsertHClassLayoutDesc(ProfileType type, bool root)
904514f5e3Sopenharmony_ci{
914514f5e3Sopenharmony_ci    auto iter = transitionLayout_.find(type);
924514f5e3Sopenharmony_ci    if (iter != transitionLayout_.end()) {
934514f5e3Sopenharmony_ci        return iter->second;
944514f5e3Sopenharmony_ci    } else {
954514f5e3Sopenharmony_ci        HClassLayoutDesc *layout;
964514f5e3Sopenharmony_ci        if (root) {
974514f5e3Sopenharmony_ci            layout = new RootHClassLayoutDesc(type);
984514f5e3Sopenharmony_ci        } else {
994514f5e3Sopenharmony_ci            layout = new ChildHClassLayoutDesc(type);
1004514f5e3Sopenharmony_ci        }
1014514f5e3Sopenharmony_ci        transitionLayout_.emplace(type, layout);
1024514f5e3Sopenharmony_ci        return layout;
1034514f5e3Sopenharmony_ci    }
1044514f5e3Sopenharmony_ci}
1054514f5e3Sopenharmony_ci
1064514f5e3Sopenharmony_cibool PGOHClassTreeDesc::DumpForRoot(JSTaggedType root, ProfileType rootType)
1074514f5e3Sopenharmony_ci{
1084514f5e3Sopenharmony_ci    ASSERT(rootType.IsRootType());
1094514f5e3Sopenharmony_ci    HClassLayoutDesc *rootLayout;
1104514f5e3Sopenharmony_ci    auto iter = transitionLayout_.find(rootType);
1114514f5e3Sopenharmony_ci    auto rootHClass = JSHClass::Cast(JSTaggedValue(root).GetTaggedObject());
1124514f5e3Sopenharmony_ci    if (iter != transitionLayout_.end()) {
1134514f5e3Sopenharmony_ci        rootLayout = iter->second;
1144514f5e3Sopenharmony_ci        return JSHClass::UpdateRootLayoutDescByPGO(rootHClass, rootLayout);
1154514f5e3Sopenharmony_ci    } else {
1164514f5e3Sopenharmony_ci        rootLayout = new RootHClassLayoutDesc(rootType, rootHClass->GetObjectType(),
1174514f5e3Sopenharmony_ci                                              rootHClass->GetObjectSizeExcludeInlinedProps());
1184514f5e3Sopenharmony_ci        transitionLayout_.emplace(rootType, rootLayout);
1194514f5e3Sopenharmony_ci    }
1204514f5e3Sopenharmony_ci
1214514f5e3Sopenharmony_ci    return JSHClass::DumpRootHClassByPGO(rootHClass, rootLayout);
1224514f5e3Sopenharmony_ci}
1234514f5e3Sopenharmony_ci
1244514f5e3Sopenharmony_cibool PGOHClassTreeDesc::DumpForChild(JSTaggedType child, ProfileType childType)
1254514f5e3Sopenharmony_ci{
1264514f5e3Sopenharmony_ci    ASSERT(!childType.IsRootType());
1274514f5e3Sopenharmony_ci    auto childHClass = JSHClass::Cast(JSTaggedValue(child).GetTaggedObject());
1284514f5e3Sopenharmony_ci
1294514f5e3Sopenharmony_ci    HClassLayoutDesc *childLayout;
1304514f5e3Sopenharmony_ci    auto iter = transitionLayout_.find(childType);
1314514f5e3Sopenharmony_ci    if (iter != transitionLayout_.end()) {
1324514f5e3Sopenharmony_ci        childLayout = iter->second;
1334514f5e3Sopenharmony_ci        return JSHClass::UpdateChildLayoutDescByPGO(childHClass, childLayout);
1344514f5e3Sopenharmony_ci    } else {
1354514f5e3Sopenharmony_ci        childLayout = new ChildHClassLayoutDesc(childType);
1364514f5e3Sopenharmony_ci        transitionLayout_.emplace(childType, childLayout);
1374514f5e3Sopenharmony_ci        return JSHClass::DumpChildHClassByPGO(childHClass, childLayout);
1384514f5e3Sopenharmony_ci    }
1394514f5e3Sopenharmony_ci}
1404514f5e3Sopenharmony_ci
1414514f5e3Sopenharmony_cibool PGOHClassTreeDesc::UpdateLayout(JSTaggedType curHClass, ProfileType curType)
1424514f5e3Sopenharmony_ci{
1434514f5e3Sopenharmony_ci    if (curType.IsRootType()) {
1444514f5e3Sopenharmony_ci        return DumpForRoot(curHClass, curType);
1454514f5e3Sopenharmony_ci    } else {
1464514f5e3Sopenharmony_ci        return DumpForChild(curHClass, curType);
1474514f5e3Sopenharmony_ci    }
1484514f5e3Sopenharmony_ci}
1494514f5e3Sopenharmony_ci
1504514f5e3Sopenharmony_cibool PGOHClassTreeDesc::IsDumped(ProfileType curType) const
1514514f5e3Sopenharmony_ci{
1524514f5e3Sopenharmony_ci    return transitionLayout_.find(curType) != transitionLayout_.end();
1534514f5e3Sopenharmony_ci}
1544514f5e3Sopenharmony_ci
1554514f5e3Sopenharmony_cibool PGOHClassTreeDesc::UpdateForTransition(
1564514f5e3Sopenharmony_ci    JSTaggedType parent, ProfileType parentType, JSTaggedType child, ProfileType childType)
1574514f5e3Sopenharmony_ci{
1584514f5e3Sopenharmony_ci    if (parentType.IsRootType()) {
1594514f5e3Sopenharmony_ci        if (!DumpForRoot(parent, parentType)) {
1604514f5e3Sopenharmony_ci            return false;
1614514f5e3Sopenharmony_ci        }
1624514f5e3Sopenharmony_ci    }
1634514f5e3Sopenharmony_ci    if (transitionLayout_.find(parentType) == transitionLayout_.end()) {
1644514f5e3Sopenharmony_ci        return false;
1654514f5e3Sopenharmony_ci    }
1664514f5e3Sopenharmony_ci
1674514f5e3Sopenharmony_ci    bool ret = DumpForChild(child, childType);
1684514f5e3Sopenharmony_ci    auto parentLayoutDesc = transitionLayout_.find(parentType)->second;
1694514f5e3Sopenharmony_ci    auto childLayoutDesc = transitionLayout_.find(childType)->second;
1704514f5e3Sopenharmony_ci    parentLayoutDesc->AddChildHClassLayoutDesc(childLayoutDesc->GetProfileType());
1714514f5e3Sopenharmony_ci    return ret;
1724514f5e3Sopenharmony_ci}
1734514f5e3Sopenharmony_ci
1744514f5e3Sopenharmony_civoid HClassLayoutDesc::Merge(const HClassLayoutDesc *from)
1754514f5e3Sopenharmony_ci{
1764514f5e3Sopenharmony_ci    from->IterateChilds([this] (const ProfileType &type) -> bool {
1774514f5e3Sopenharmony_ci        AddChildHClassLayoutDesc(type);
1784514f5e3Sopenharmony_ci        return true;
1794514f5e3Sopenharmony_ci    });
1804514f5e3Sopenharmony_ci}
1814514f5e3Sopenharmony_ci
1824514f5e3Sopenharmony_civoid HClassLayoutDesc::InsertKeyAndDesc(const PGOHandler &handler, PropertyDesc &desc)
1834514f5e3Sopenharmony_ci{
1844514f5e3Sopenharmony_ci    PGOHandler oldHandler = desc.second;
1854514f5e3Sopenharmony_ci    if (oldHandler == handler) {
1864514f5e3Sopenharmony_ci        return;
1874514f5e3Sopenharmony_ci    }
1884514f5e3Sopenharmony_ci    auto oldTrackType = oldHandler.GetTrackType();
1894514f5e3Sopenharmony_ci    auto newTrackType = handler.GetTrackType();
1904514f5e3Sopenharmony_ci    if (oldTrackType == newTrackType) {
1914514f5e3Sopenharmony_ci        desc.second.SetPropertyMeta(handler.GetPropertyMeta());
1924514f5e3Sopenharmony_ci        return;
1934514f5e3Sopenharmony_ci    }
1944514f5e3Sopenharmony_ci
1954514f5e3Sopenharmony_ci    switch (oldTrackType) {
1964514f5e3Sopenharmony_ci        case TrackType::TAGGED:
1974514f5e3Sopenharmony_ci            desc.second.SetPropertyMeta(handler.GetPropertyMeta());
1984514f5e3Sopenharmony_ci            break;
1994514f5e3Sopenharmony_ci        case TrackType::NONE:
2004514f5e3Sopenharmony_ci        case TrackType::INT:
2014514f5e3Sopenharmony_ci        case TrackType::DOUBLE:
2024514f5e3Sopenharmony_ci            if (newTrackType != TrackType::TAGGED) {
2034514f5e3Sopenharmony_ci                newTrackType = static_cast<TrackType>(static_cast<uint8_t>(newTrackType) |
2044514f5e3Sopenharmony_ci                    static_cast<uint8_t>(oldTrackType));
2054514f5e3Sopenharmony_ci            }
2064514f5e3Sopenharmony_ci            desc.second = PGOHandler(newTrackType, handler.GetPropertyMeta());
2074514f5e3Sopenharmony_ci            break;
2084514f5e3Sopenharmony_ci        default:
2094514f5e3Sopenharmony_ci            break;
2104514f5e3Sopenharmony_ci    }
2114514f5e3Sopenharmony_ci}
2124514f5e3Sopenharmony_ci
2134514f5e3Sopenharmony_civoid RootHClassLayoutDesc::Merge(const HClassLayoutDesc *from)
2144514f5e3Sopenharmony_ci{
2154514f5e3Sopenharmony_ci    ASSERT(from->GetProfileType() == GetProfileType());
2164514f5e3Sopenharmony_ci    ASSERT(from->GetProfileType().IsRootType());
2174514f5e3Sopenharmony_ci    auto fromDesc = reinterpret_cast<const RootHClassLayoutDesc *>(from);
2184514f5e3Sopenharmony_ci    fromDesc->IterateProps([this] (const PropertyDesc &desc) {
2194514f5e3Sopenharmony_ci        InsertKeyAndDesc(desc.first, desc.second);
2204514f5e3Sopenharmony_ci    });
2214514f5e3Sopenharmony_ci    HClassLayoutDesc::Merge(from);
2224514f5e3Sopenharmony_ci}
2234514f5e3Sopenharmony_ci
2244514f5e3Sopenharmony_civoid RootHClassLayoutDesc::InsertKeyAndDesc(const CString &key, const PGOHandler &handler)
2254514f5e3Sopenharmony_ci{
2264514f5e3Sopenharmony_ci    if (!UpdateKeyAndDesc(key, handler)) {
2274514f5e3Sopenharmony_ci        layoutDesc_.emplace_back(key, handler);
2284514f5e3Sopenharmony_ci    }
2294514f5e3Sopenharmony_ci}
2304514f5e3Sopenharmony_ci
2314514f5e3Sopenharmony_cibool RootHClassLayoutDesc::UpdateKeyAndDesc(const CString &key, const PGOHandler &handler)
2324514f5e3Sopenharmony_ci{
2334514f5e3Sopenharmony_ci    for (auto &iter : layoutDesc_) {
2344514f5e3Sopenharmony_ci        if (iter.first == key) {
2354514f5e3Sopenharmony_ci            HClassLayoutDesc::InsertKeyAndDesc(handler, iter);
2364514f5e3Sopenharmony_ci            return true;
2374514f5e3Sopenharmony_ci        }
2384514f5e3Sopenharmony_ci    }
2394514f5e3Sopenharmony_ci    return false;
2404514f5e3Sopenharmony_ci}
2414514f5e3Sopenharmony_ci
2424514f5e3Sopenharmony_civoid ChildHClassLayoutDesc::Merge(const HClassLayoutDesc *from)
2434514f5e3Sopenharmony_ci{
2444514f5e3Sopenharmony_ci    ASSERT(from->GetProfileType() == GetProfileType());
2454514f5e3Sopenharmony_ci    ASSERT(!from->GetProfileType().IsRootType());
2464514f5e3Sopenharmony_ci    auto fromDesc = reinterpret_cast<const ChildHClassLayoutDesc *>(from);
2474514f5e3Sopenharmony_ci    auto fromPropDesc = fromDesc->GetPropertyDesc();
2484514f5e3Sopenharmony_ci    InsertKeyAndDesc(fromPropDesc.first, fromPropDesc.second);
2494514f5e3Sopenharmony_ci    HClassLayoutDesc::Merge(from);
2504514f5e3Sopenharmony_ci}
2514514f5e3Sopenharmony_ci
2524514f5e3Sopenharmony_civoid ChildHClassLayoutDesc::InsertKeyAndDesc(const CString &key, const PGOHandler &handler)
2534514f5e3Sopenharmony_ci{
2544514f5e3Sopenharmony_ci    if (!UpdateKeyAndDesc(key, handler)) {
2554514f5e3Sopenharmony_ci        propertyDesc_ = PropertyDesc(key, handler);
2564514f5e3Sopenharmony_ci    }
2574514f5e3Sopenharmony_ci}
2584514f5e3Sopenharmony_ci
2594514f5e3Sopenharmony_cibool ChildHClassLayoutDesc::UpdateKeyAndDesc(const CString &key, const PGOHandler &handler)
2604514f5e3Sopenharmony_ci{
2614514f5e3Sopenharmony_ci    if (propertyDesc_.first == key) {
2624514f5e3Sopenharmony_ci        HClassLayoutDesc::InsertKeyAndDesc(handler, propertyDesc_);
2634514f5e3Sopenharmony_ci        return true;
2644514f5e3Sopenharmony_ci    }
2654514f5e3Sopenharmony_ci    return false;
2664514f5e3Sopenharmony_ci}
2674514f5e3Sopenharmony_ci} // namespace panda::ecmascript::pgo
268