14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021-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 <algorithm>
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/ecma_context.h"
194514f5e3Sopenharmony_ci#include "ecmascript/global_env_constants-inl.h"
204514f5e3Sopenharmony_ci#include "ecmascript/pgo_profiler/pgo_profiler.h"
214514f5e3Sopenharmony_ci#include "ecmascript/pgo_profiler/pgo_profiler_layout.h"
224514f5e3Sopenharmony_ci#include "ecmascript/ic/proto_change_details.h"
234514f5e3Sopenharmony_ci#include "ecmascript/js_function.h"
244514f5e3Sopenharmony_ci#include "ecmascript/js_object-inl.h"
254514f5e3Sopenharmony_ci
264514f5e3Sopenharmony_cinamespace panda::ecmascript {
274514f5e3Sopenharmony_ciusing ProfileType = pgo::ProfileType;
284514f5e3Sopenharmony_ci
294514f5e3Sopenharmony_ciJSHandle<TransitionsDictionary> TransitionsDictionary::PutIfAbsent(const JSThread *thread,
304514f5e3Sopenharmony_ci                                                                   const JSHandle<TransitionsDictionary> &dictionary,
314514f5e3Sopenharmony_ci                                                                   const JSHandle<JSTaggedValue> &key,
324514f5e3Sopenharmony_ci                                                                   const JSHandle<JSTaggedValue> &value,
334514f5e3Sopenharmony_ci                                                                   const JSHandle<JSTaggedValue> &metaData)
344514f5e3Sopenharmony_ci{
354514f5e3Sopenharmony_ci    uint32_t hash = static_cast<uint32_t>(TransitionsDictionary::Hash(key.GetTaggedValue(), metaData.GetTaggedValue()));
364514f5e3Sopenharmony_ci
374514f5e3Sopenharmony_ci    /* no need to add key if exist */
384514f5e3Sopenharmony_ci    int entry = dictionary->FindEntry(key.GetTaggedValue(), metaData.GetTaggedValue());
394514f5e3Sopenharmony_ci    if (entry != -1) {
404514f5e3Sopenharmony_ci        if (dictionary->GetValue(entry).IsUndefined()) {
414514f5e3Sopenharmony_ci            JSTaggedValue weakValue = JSTaggedValue(value->CreateAndGetWeakRef());
424514f5e3Sopenharmony_ci            dictionary->SetValue(thread, entry, weakValue);
434514f5e3Sopenharmony_ci        }
444514f5e3Sopenharmony_ci        return dictionary;
454514f5e3Sopenharmony_ci    }
464514f5e3Sopenharmony_ci
474514f5e3Sopenharmony_ci    // Check whether the dictionary should be extended.
484514f5e3Sopenharmony_ci    JSHandle<TransitionsDictionary> newDictionary(HashTableT::GrowHashTable(thread, dictionary));
494514f5e3Sopenharmony_ci    // Compute the key object.
504514f5e3Sopenharmony_ci    entry = newDictionary->FindInsertIndex(hash);
514514f5e3Sopenharmony_ci    JSTaggedValue val = value.GetTaggedValue();
524514f5e3Sopenharmony_ci    newDictionary->SetEntry(thread, entry, key.GetTaggedValue(), val, metaData.GetTaggedValue());
534514f5e3Sopenharmony_ci
544514f5e3Sopenharmony_ci    newDictionary->IncreaseEntries(thread);
554514f5e3Sopenharmony_ci    return newDictionary;
564514f5e3Sopenharmony_ci}
574514f5e3Sopenharmony_ci
584514f5e3Sopenharmony_ciint TransitionsDictionary::FindEntry(const JSTaggedValue &key, const JSTaggedValue &metaData)
594514f5e3Sopenharmony_ci{
604514f5e3Sopenharmony_ci    size_t size = static_cast<size_t>(Size());
614514f5e3Sopenharmony_ci    uint32_t count = 1;
624514f5e3Sopenharmony_ci    int32_t hash = TransitionsDictionary::Hash(key, metaData);
634514f5e3Sopenharmony_ci    // GrowHashTable will guarantee the hash table is never full.
644514f5e3Sopenharmony_ci    for (uint32_t entry = GetFirstPosition(hash, size);; entry = GetNextPosition(entry, count++, size)) {
654514f5e3Sopenharmony_ci        JSTaggedValue element = GetKey(entry);
664514f5e3Sopenharmony_ci        if (element.IsHole()) {
674514f5e3Sopenharmony_ci            continue;
684514f5e3Sopenharmony_ci        }
694514f5e3Sopenharmony_ci        if (element.IsUndefined()) {
704514f5e3Sopenharmony_ci            return -1;
714514f5e3Sopenharmony_ci        }
724514f5e3Sopenharmony_ci
734514f5e3Sopenharmony_ci        if (TransitionsDictionary::IsMatch(key, metaData, element, GetAttributes(entry).GetWeakRawValue())) {
744514f5e3Sopenharmony_ci            return static_cast<int>(entry);
754514f5e3Sopenharmony_ci        }
764514f5e3Sopenharmony_ci    }
774514f5e3Sopenharmony_ci    return -1;
784514f5e3Sopenharmony_ci}
794514f5e3Sopenharmony_ci
804514f5e3Sopenharmony_ciJSHandle<TransitionsDictionary> TransitionsDictionary::Remove(const JSThread *thread,
814514f5e3Sopenharmony_ci                                                              const JSHandle<TransitionsDictionary> &table,
824514f5e3Sopenharmony_ci                                                              const JSHandle<JSTaggedValue> &key,
834514f5e3Sopenharmony_ci                                                              const JSTaggedValue &metaData)
844514f5e3Sopenharmony_ci{
854514f5e3Sopenharmony_ci    int entry = table->FindEntry(key.GetTaggedValue(), metaData);
864514f5e3Sopenharmony_ci    if (entry == -1) {
874514f5e3Sopenharmony_ci        return table;
884514f5e3Sopenharmony_ci    }
894514f5e3Sopenharmony_ci
904514f5e3Sopenharmony_ci    table->RemoveElement(thread, entry);
914514f5e3Sopenharmony_ci    return TransitionsDictionary::Shrink(thread, table);
924514f5e3Sopenharmony_ci}
934514f5e3Sopenharmony_ci
944514f5e3Sopenharmony_civoid TransitionsDictionary::Rehash(const JSThread *thread, TransitionsDictionary *newTable)
954514f5e3Sopenharmony_ci{
964514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
974514f5e3Sopenharmony_ci    if (newTable == nullptr) {
984514f5e3Sopenharmony_ci        return;
994514f5e3Sopenharmony_ci    }
1004514f5e3Sopenharmony_ci    int size = this->Size();
1014514f5e3Sopenharmony_ci    // Rehash elements to new table
1024514f5e3Sopenharmony_ci    int entryCount = 0;
1034514f5e3Sopenharmony_ci    for (int i = 0; i < size; i++) {
1044514f5e3Sopenharmony_ci        int fromIndex = GetEntryIndex(i);
1054514f5e3Sopenharmony_ci        JSTaggedValue k = this->GetKey(i);
1064514f5e3Sopenharmony_ci        JSTaggedValue v = this->GetValue(i);
1074514f5e3Sopenharmony_ci        if (IsKey(k) && TransitionsDictionary::CheckWeakExist(v)) {
1084514f5e3Sopenharmony_ci            uint32_t hash = static_cast<uint32_t>(TransitionsDictionary::Hash(k, this->GetAttributes(i)));
1094514f5e3Sopenharmony_ci            int insertionIndex = GetEntryIndex(newTable->FindInsertIndex(hash));
1104514f5e3Sopenharmony_ci            JSTaggedValue tv = Get(fromIndex);
1114514f5e3Sopenharmony_ci            newTable->Set(thread, insertionIndex, tv);
1124514f5e3Sopenharmony_ci            for (int j = 1; j < TransitionsDictionary::ENTRY_SIZE; j++) {
1134514f5e3Sopenharmony_ci                tv = Get(fromIndex + j);
1144514f5e3Sopenharmony_ci                newTable->Set(thread, insertionIndex + j, tv);
1154514f5e3Sopenharmony_ci            }
1164514f5e3Sopenharmony_ci            entryCount++;
1174514f5e3Sopenharmony_ci        }
1184514f5e3Sopenharmony_ci    }
1194514f5e3Sopenharmony_ci    newTable->SetEntriesCount(thread, entryCount);
1204514f5e3Sopenharmony_ci    newTable->SetHoleEntriesCount(thread, 0);
1214514f5e3Sopenharmony_ci}
1224514f5e3Sopenharmony_ci
1234514f5e3Sopenharmony_civoid JSHClass::InitializeWithDefaultValue(const JSThread *thread, uint32_t size, JSType type, uint32_t inlinedProps)
1244514f5e3Sopenharmony_ci{
1254514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
1264514f5e3Sopenharmony_ci    ClearBitField();
1274514f5e3Sopenharmony_ci    if (IsJSTypeObject(type)) {
1284514f5e3Sopenharmony_ci        SetObjectSize(size + inlinedProps * JSTaggedValue::TaggedTypeSize());
1294514f5e3Sopenharmony_ci        SetInlinedPropsStart(size);
1304514f5e3Sopenharmony_ci    } else {
1314514f5e3Sopenharmony_ci        SetObjectSize(size);
1324514f5e3Sopenharmony_ci    }
1334514f5e3Sopenharmony_ci    SetLayout(thread, JSTaggedValue::Null());
1344514f5e3Sopenharmony_ci    if (type >= JSType::JS_FUNCTION_FIRST && type <= JSType::JS_FUNCTION_LAST) {
1354514f5e3Sopenharmony_ci        SetIsJSFunction(true);
1364514f5e3Sopenharmony_ci    }
1374514f5e3Sopenharmony_ci    SetPrototype(thread, JSTaggedValue::Null());
1384514f5e3Sopenharmony_ci
1394514f5e3Sopenharmony_ci    SetObjectType(type);
1404514f5e3Sopenharmony_ci    SetExtensible(true);
1414514f5e3Sopenharmony_ci    SetIsPrototype(false);
1424514f5e3Sopenharmony_ci    SetHasDeleteProperty(false);
1434514f5e3Sopenharmony_ci    SetIsAllTaggedProp(true);
1444514f5e3Sopenharmony_ci    SetElementsKind(ElementsKind::GENERIC);
1454514f5e3Sopenharmony_ci    SetTransitions(thread, JSTaggedValue::Undefined());
1464514f5e3Sopenharmony_ci    SetParent(thread, JSTaggedValue::Undefined());
1474514f5e3Sopenharmony_ci    SetProtoChangeMarker(thread, JSTaggedValue::Null());
1484514f5e3Sopenharmony_ci    SetProtoChangeDetails(thread, JSTaggedValue::Null());
1494514f5e3Sopenharmony_ci    SetEnumCache(thread, JSTaggedValue::Null());
1504514f5e3Sopenharmony_ci    SetLevel(0);
1514514f5e3Sopenharmony_ci}
1524514f5e3Sopenharmony_ci
1534514f5e3Sopenharmony_cibool JSHClass::IsJSTypeShared(JSType type)
1544514f5e3Sopenharmony_ci{
1554514f5e3Sopenharmony_ci    bool isShared = false;
1564514f5e3Sopenharmony_ci    switch (type) {
1574514f5e3Sopenharmony_ci        case JSType::JS_SHARED_OBJECT:
1584514f5e3Sopenharmony_ci        case JSType::JS_SHARED_FUNCTION:
1594514f5e3Sopenharmony_ci        case JSType::JS_SHARED_ASYNC_FUNCTION:
1604514f5e3Sopenharmony_ci        case JSType::JS_SHARED_SET:
1614514f5e3Sopenharmony_ci        case JSType::JS_SHARED_MAP:
1624514f5e3Sopenharmony_ci        case JSType::JS_SHARED_ARRAY:
1634514f5e3Sopenharmony_ci        case JSType::JS_SHARED_TYPED_ARRAY:
1644514f5e3Sopenharmony_ci        case JSType::JS_SHARED_INT8_ARRAY:
1654514f5e3Sopenharmony_ci        case JSType::JS_SHARED_UINT8_ARRAY:
1664514f5e3Sopenharmony_ci        case JSType::JS_SHARED_UINT8_CLAMPED_ARRAY:
1674514f5e3Sopenharmony_ci        case JSType::JS_SHARED_INT16_ARRAY:
1684514f5e3Sopenharmony_ci        case JSType::JS_SHARED_UINT16_ARRAY:
1694514f5e3Sopenharmony_ci        case JSType::JS_SHARED_INT32_ARRAY:
1704514f5e3Sopenharmony_ci        case JSType::JS_SHARED_UINT32_ARRAY:
1714514f5e3Sopenharmony_ci        case JSType::JS_SHARED_FLOAT32_ARRAY:
1724514f5e3Sopenharmony_ci        case JSType::JS_SHARED_FLOAT64_ARRAY:
1734514f5e3Sopenharmony_ci        case JSType::JS_SHARED_BIGINT64_ARRAY:
1744514f5e3Sopenharmony_ci        case JSType::JS_SHARED_BIGUINT64_ARRAY:
1754514f5e3Sopenharmony_ci        case JSType::JS_SENDABLE_ARRAY_BUFFER:
1764514f5e3Sopenharmony_ci        case JSType::BIGINT:
1774514f5e3Sopenharmony_ci        case JSType::LINE_STRING:
1784514f5e3Sopenharmony_ci        case JSType::CONSTANT_STRING:
1794514f5e3Sopenharmony_ci        case JSType::SLICED_STRING:
1804514f5e3Sopenharmony_ci        case JSType::TREE_STRING:
1814514f5e3Sopenharmony_ci            isShared = true;
1824514f5e3Sopenharmony_ci            break;
1834514f5e3Sopenharmony_ci        default:
1844514f5e3Sopenharmony_ci            break;
1854514f5e3Sopenharmony_ci    }
1864514f5e3Sopenharmony_ci    return isShared;
1874514f5e3Sopenharmony_ci}
1884514f5e3Sopenharmony_ci
1894514f5e3Sopenharmony_ci// class JSHClass
1904514f5e3Sopenharmony_civoid JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type, uint32_t inlinedProps)
1914514f5e3Sopenharmony_ci{
1924514f5e3Sopenharmony_ci    InitializeWithDefaultValue(thread, size, type, inlinedProps);
1934514f5e3Sopenharmony_ci    if (IsJSTypeObject(type)) {
1944514f5e3Sopenharmony_ci        SetLayout(thread, thread->GlobalConstants()->GetEmptyLayoutInfo());
1954514f5e3Sopenharmony_ci    }
1964514f5e3Sopenharmony_ci}
1974514f5e3Sopenharmony_ci
1984514f5e3Sopenharmony_ci// for sharedHeap
1994514f5e3Sopenharmony_civoid JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type,
2004514f5e3Sopenharmony_ci    uint32_t inlinedProps, const JSHandle<JSTaggedValue> &layout)
2014514f5e3Sopenharmony_ci{
2024514f5e3Sopenharmony_ci    InitializeWithDefaultValue(thread, size, type, inlinedProps);
2034514f5e3Sopenharmony_ci    if (IsJSTypeObject(type)) {
2044514f5e3Sopenharmony_ci        SetLayout(thread, layout);
2054514f5e3Sopenharmony_ci    }
2064514f5e3Sopenharmony_ci    if (IsJSTypeShared(type)) {
2074514f5e3Sopenharmony_ci        SetIsJSShared(true);
2084514f5e3Sopenharmony_ci    }
2094514f5e3Sopenharmony_ci}
2104514f5e3Sopenharmony_ci
2114514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::Clone(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
2124514f5e3Sopenharmony_ci                                   bool withoutInlinedProperties, uint32_t incInlinedProperties)
2134514f5e3Sopenharmony_ci{
2144514f5e3Sopenharmony_ci    JSType type = jshclass->GetObjectType();
2154514f5e3Sopenharmony_ci    uint32_t size = IsJSTypeObject(type) ? jshclass->GetInlinedPropsStartSize() : jshclass->GetObjectSize();
2164514f5e3Sopenharmony_ci    uint32_t numInlinedProps = withoutInlinedProperties ? 0 : jshclass->GetInlinedProperties() + incInlinedProperties;
2174514f5e3Sopenharmony_ci    JSHandle<JSHClass> newJsHClass;
2184514f5e3Sopenharmony_ci    if (jshclass.GetTaggedValue().IsInSharedHeap()) {
2194514f5e3Sopenharmony_ci        newJsHClass = thread->GetEcmaVM()->GetFactory()->NewSEcmaHClass(size, type, numInlinedProps);
2204514f5e3Sopenharmony_ci    } else {
2214514f5e3Sopenharmony_ci        newJsHClass = thread->GetEcmaVM()->GetFactory()->NewEcmaHClass(size, type, numInlinedProps);
2224514f5e3Sopenharmony_ci    }
2234514f5e3Sopenharmony_ci    // Copy all
2244514f5e3Sopenharmony_ci    newJsHClass->Copy(thread, *jshclass);
2254514f5e3Sopenharmony_ci    newJsHClass->SetTransitions(thread, JSTaggedValue::Undefined());
2264514f5e3Sopenharmony_ci    newJsHClass->SetParent(thread, JSTaggedValue::Undefined());
2274514f5e3Sopenharmony_ci    newJsHClass->SetProtoChangeDetails(thread, JSTaggedValue::Null());
2284514f5e3Sopenharmony_ci    newJsHClass->SetEnumCache(thread, JSTaggedValue::Null());
2294514f5e3Sopenharmony_ci    // reuse Attributes first.
2304514f5e3Sopenharmony_ci    newJsHClass->SetLayout(thread, jshclass->GetLayout());
2314514f5e3Sopenharmony_ci
2324514f5e3Sopenharmony_ci    if (jshclass->IsTS()) {
2334514f5e3Sopenharmony_ci        newJsHClass->SetTS(false);
2344514f5e3Sopenharmony_ci    }
2354514f5e3Sopenharmony_ci
2364514f5e3Sopenharmony_ci    return newJsHClass;
2374514f5e3Sopenharmony_ci}
2384514f5e3Sopenharmony_ci
2394514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::CloneWithElementsKind(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
2404514f5e3Sopenharmony_ci                                                   const ElementsKind kind, bool isPrototype)
2414514f5e3Sopenharmony_ci{
2424514f5e3Sopenharmony_ci    JSHandle<JSHClass> newHClass = Clone(thread, jshclass);
2434514f5e3Sopenharmony_ci    newHClass->SetIsPrototype(isPrototype);
2444514f5e3Sopenharmony_ci    newHClass->SetElementsKind(kind);
2454514f5e3Sopenharmony_ci    return newHClass;
2464514f5e3Sopenharmony_ci}
2474514f5e3Sopenharmony_ci
2484514f5e3Sopenharmony_ci// use for transition to dictionary
2494514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::CloneWithoutInlinedProperties(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
2504514f5e3Sopenharmony_ci{
2514514f5e3Sopenharmony_ci    return Clone(thread, jshclass, true);
2524514f5e3Sopenharmony_ci}
2534514f5e3Sopenharmony_ci
2544514f5e3Sopenharmony_civoid JSHClass::TransitionElementsToDictionary(const JSThread *thread, const JSHandle<JSObject> &obj)
2554514f5e3Sopenharmony_ci{
2564514f5e3Sopenharmony_ci    // property transition to slow first
2574514f5e3Sopenharmony_ci    if (!obj->GetJSHClass()->IsDictionaryMode()) {
2584514f5e3Sopenharmony_ci        JSObject::TransitionToDictionary(thread, obj);
2594514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
2604514f5e3Sopenharmony_ci    } else {
2614514f5e3Sopenharmony_ci        TransitionToDictionary(thread, obj);
2624514f5e3Sopenharmony_ci    }
2634514f5e3Sopenharmony_ci    obj->GetJSHClass()->SetIsDictionaryElement(true);
2644514f5e3Sopenharmony_ci    obj->GetJSHClass()->SetIsStableElements(false);
2654514f5e3Sopenharmony_ci    obj->GetJSHClass()->SetElementsKind(ElementsKind::DICTIONARY);
2664514f5e3Sopenharmony_ci}
2674514f5e3Sopenharmony_ci
2684514f5e3Sopenharmony_civoid JSHClass::OptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj)
2694514f5e3Sopenharmony_ci{
2704514f5e3Sopenharmony_ci    if (obj->GetJSHClass()->IsDictionaryMode()) {
2714514f5e3Sopenharmony_ci        JSObject::OptimizeAsFastProperties(thread, obj);
2724514f5e3Sopenharmony_ci    } else {
2734514f5e3Sopenharmony_ci        OptimizeAsFastProperties(thread, obj);
2744514f5e3Sopenharmony_ci    }
2754514f5e3Sopenharmony_ci    obj->GetJSHClass()->SetIsDictionaryElement(false);
2764514f5e3Sopenharmony_ci    obj->GetJSHClass()->SetIsStableElements(true);
2774514f5e3Sopenharmony_ci    obj->GetJSHClass()->SetElementsKind(ElementsKind::HOLE_TAGGED);
2784514f5e3Sopenharmony_ci}
2794514f5e3Sopenharmony_ci
2804514f5e3Sopenharmony_civoid JSHClass::AddProperty(const JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
2814514f5e3Sopenharmony_ci                           const PropertyAttributes &attr, const Representation &rep)
2824514f5e3Sopenharmony_ci{
2834514f5e3Sopenharmony_ci    JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
2844514f5e3Sopenharmony_ci    auto metadata = JSTaggedValue(attr.GetPropertyMetaData());
2854514f5e3Sopenharmony_ci    JSHClass *newClass = jshclass->FindTransitions(key.GetTaggedValue(), metadata, rep);
2864514f5e3Sopenharmony_ci    if (newClass != nullptr) {
2874514f5e3Sopenharmony_ci        // The transition hclass from AOT, which does not have a prototype, needs to be reset here.
2884514f5e3Sopenharmony_ci        if (newClass->IsTS()) {
2894514f5e3Sopenharmony_ci            newClass->SetPrototype(thread, jshclass->GetPrototype());
2904514f5e3Sopenharmony_ci        }
2914514f5e3Sopenharmony_ci        // Because we currently only supports Fast ElementsKind
2924514f5e3Sopenharmony_ci        RestoreElementsKindToGeneric(newClass);
2934514f5e3Sopenharmony_ci        obj->SynchronizedSetClass(thread, newClass);
2944514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_IC
2954514f5e3Sopenharmony_ci        // The transition hclass from AOT, which does not have protochangemarker, needs to be reset here
2964514f5e3Sopenharmony_ci        JSHandle<JSHClass> newHClass = JSHandle<JSHClass>(thread, newClass);
2974514f5e3Sopenharmony_ci        if (newClass->IsTS() && newClass->IsPrototype()) {
2984514f5e3Sopenharmony_ci            if (JSHClass::IsNeedNotifyHclassChangedForAotTransition(thread, jshclass, key.GetTaggedValue())) {
2994514f5e3Sopenharmony_ci                JSHClass::EnableProtoChangeMarker(thread, newHClass);
3004514f5e3Sopenharmony_ci                JSHClass::NotifyHclassChanged(thread, jshclass, newHClass, key.GetTaggedValue());
3014514f5e3Sopenharmony_ci            } else {
3024514f5e3Sopenharmony_ci                JSHClass::RefreshUsers(thread, jshclass, newHClass);
3034514f5e3Sopenharmony_ci            }
3044514f5e3Sopenharmony_ci            JSHClass::EnablePHCProtoChangeMarker(thread, newHClass);
3054514f5e3Sopenharmony_ci        } else {
3064514f5e3Sopenharmony_ci            JSHClass::NotifyHclassChanged(thread, jshclass, newHClass, key.GetTaggedValue());
3074514f5e3Sopenharmony_ci        }
3084514f5e3Sopenharmony_ci#endif
3094514f5e3Sopenharmony_ci        return;
3104514f5e3Sopenharmony_ci    }
3114514f5e3Sopenharmony_ci    JSHandle<JSHClass> newJsHClass = JSHClass::Clone(thread, jshclass);
3124514f5e3Sopenharmony_ci    RestoreElementsKindToGeneric(*newJsHClass);
3134514f5e3Sopenharmony_ci    AddPropertyToNewHClass(thread, jshclass, newJsHClass, key, attr);
3144514f5e3Sopenharmony_ci    // update hclass in object.
3154514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_IC
3164514f5e3Sopenharmony_ci    JSHClass::NotifyHclassChanged(thread, jshclass, newJsHClass, key.GetTaggedValue());
3174514f5e3Sopenharmony_ci#endif
3184514f5e3Sopenharmony_ci    // Because we currently only supports Fast ElementsKind
3194514f5e3Sopenharmony_ci    obj->SynchronizedSetClass(thread, *newJsHClass);
3204514f5e3Sopenharmony_ci}
3214514f5e3Sopenharmony_ci
3224514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::TransitionExtension(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
3234514f5e3Sopenharmony_ci{
3244514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> key(thread->GlobalConstants()->GetHandledPreventExtensionsString());
3254514f5e3Sopenharmony_ci    {
3264514f5e3Sopenharmony_ci        auto *newClass = jshclass->FindTransitions(key.GetTaggedValue(), JSTaggedValue(0), Representation::NONE);
3274514f5e3Sopenharmony_ci        if (newClass != nullptr) {
3284514f5e3Sopenharmony_ci            newClass->SetPrototype(thread, jshclass->GetPrototype());
3294514f5e3Sopenharmony_ci            return JSHandle<JSHClass>(thread, newClass);
3304514f5e3Sopenharmony_ci        }
3314514f5e3Sopenharmony_ci    }
3324514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
3334514f5e3Sopenharmony_ci    // 2. new a hclass
3344514f5e3Sopenharmony_ci    JSHandle<JSHClass> newJsHClass = JSHClass::Clone(thread, jshclass);
3354514f5e3Sopenharmony_ci    newJsHClass->SetExtensible(false);
3364514f5e3Sopenharmony_ci
3374514f5e3Sopenharmony_ci    JSTaggedValue attrs = newJsHClass->GetLayout();
3384514f5e3Sopenharmony_ci    {
3394514f5e3Sopenharmony_ci        JSMutableHandle<LayoutInfo> layoutInfoHandle(thread, attrs);
3404514f5e3Sopenharmony_ci        layoutInfoHandle.Update(factory->CopyLayoutInfo(layoutInfoHandle).GetTaggedValue());
3414514f5e3Sopenharmony_ci        newJsHClass->SetLayout(thread, layoutInfoHandle);
3424514f5e3Sopenharmony_ci    }
3434514f5e3Sopenharmony_ci
3444514f5e3Sopenharmony_ci    // 3. Add newClass to old hclass's parent's transitions.
3454514f5e3Sopenharmony_ci    AddExtensionTransitions(thread, jshclass, newJsHClass, key);
3464514f5e3Sopenharmony_ci    // parent is the same as jshclass, already copy
3474514f5e3Sopenharmony_ci    return newJsHClass;
3484514f5e3Sopenharmony_ci}
3494514f5e3Sopenharmony_ci
3504514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::TransitionProto(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
3514514f5e3Sopenharmony_ci                                             const JSHandle<JSTaggedValue> &proto, bool isChangeProto)
3524514f5e3Sopenharmony_ci{
3534514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> key(thread->GlobalConstants()->GetHandledPrototypeString());
3544514f5e3Sopenharmony_ci
3554514f5e3Sopenharmony_ci    {
3564514f5e3Sopenharmony_ci        auto *newClass = jshclass->FindProtoTransitions(key.GetTaggedValue(), proto.GetTaggedValue());
3574514f5e3Sopenharmony_ci        if (newClass != nullptr) {
3584514f5e3Sopenharmony_ci            return JSHandle<JSHClass>(thread, newClass);
3594514f5e3Sopenharmony_ci        }
3604514f5e3Sopenharmony_ci        newClass = FindTransitionProtoForAOT(thread, jshclass, proto);
3614514f5e3Sopenharmony_ci        if (newClass != nullptr) {
3624514f5e3Sopenharmony_ci            return JSHandle<JSHClass>(thread, newClass);
3634514f5e3Sopenharmony_ci        }
3644514f5e3Sopenharmony_ci    }
3654514f5e3Sopenharmony_ci
3664514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
3674514f5e3Sopenharmony_ci    // 2. new a hclass
3684514f5e3Sopenharmony_ci    JSHandle<JSHClass> newJsHClass = JSHClass::Clone(thread, jshclass);
3694514f5e3Sopenharmony_ci    newJsHClass->SetPrototype(thread, proto.GetTaggedValue(), isChangeProto);
3704514f5e3Sopenharmony_ci
3714514f5e3Sopenharmony_ci    JSTaggedValue layout = newJsHClass->GetLayout();
3724514f5e3Sopenharmony_ci    {
3734514f5e3Sopenharmony_ci        JSMutableHandle<LayoutInfo> layoutInfoHandle(thread, layout);
3744514f5e3Sopenharmony_ci        layoutInfoHandle.Update(factory->CopyLayoutInfo(layoutInfoHandle).GetTaggedValue());
3754514f5e3Sopenharmony_ci        newJsHClass->SetLayout(thread, layoutInfoHandle);
3764514f5e3Sopenharmony_ci    }
3774514f5e3Sopenharmony_ci
3784514f5e3Sopenharmony_ci    // 3. Add newJsHClass to old jshclass's parent's transitions.
3794514f5e3Sopenharmony_ci    AddProtoTransitions(thread, jshclass, newJsHClass, key, proto);
3804514f5e3Sopenharmony_ci
3814514f5e3Sopenharmony_ci    // parent is the same as jshclass, already copy
3824514f5e3Sopenharmony_ci    return newJsHClass;
3834514f5e3Sopenharmony_ci}
3844514f5e3Sopenharmony_ci
3854514f5e3Sopenharmony_ci// static
3864514f5e3Sopenharmony_ciJSHClass *JSHClass::FindTransitionProtoForAOT(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
3874514f5e3Sopenharmony_ci                                              const JSHandle<JSTaggedValue> &proto)
3884514f5e3Sopenharmony_ci{
3894514f5e3Sopenharmony_ci    if (!proto->IsECMAObject()) {
3904514f5e3Sopenharmony_ci        return nullptr;
3914514f5e3Sopenharmony_ci    }
3924514f5e3Sopenharmony_ci    JSHandle<JSHClass> baseIhc(thread, proto->GetTaggedObject()->GetClass());
3934514f5e3Sopenharmony_ci    if (!jshclass->IsTS() || !baseIhc->IsTS()) {
3944514f5e3Sopenharmony_ci        return nullptr;
3954514f5e3Sopenharmony_ci    }
3964514f5e3Sopenharmony_ci    auto transitionTable = thread->GetCurrentEcmaContext()->GetFunctionProtoTransitionTable();
3974514f5e3Sopenharmony_ci    auto transHc = transitionTable->FindTransitionByHClass(thread,
3984514f5e3Sopenharmony_ci                                                           JSHandle<JSTaggedValue>(jshclass),
3994514f5e3Sopenharmony_ci                                                           JSHandle<JSTaggedValue>(baseIhc));
4004514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> transIhc(thread, transHc.first);
4014514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> transPhc(thread, transHc.second);
4024514f5e3Sopenharmony_ci    if (transIhc->IsUndefined() || transPhc->IsUndefined()) {
4034514f5e3Sopenharmony_ci        return nullptr;
4044514f5e3Sopenharmony_ci    }
4054514f5e3Sopenharmony_ci    ReBuildFunctionInheritanceRelationship(thread, proto, JSHandle<JSTaggedValue>(baseIhc), transIhc, transPhc);
4064514f5e3Sopenharmony_ci    return JSHClass::Cast(transIhc->GetTaggedObject());
4074514f5e3Sopenharmony_ci}
4084514f5e3Sopenharmony_ci
4094514f5e3Sopenharmony_ci// static
4104514f5e3Sopenharmony_civoid JSHClass::ReBuildFunctionInheritanceRelationship(const JSThread *thread,
4114514f5e3Sopenharmony_ci                                                      const JSHandle<JSTaggedValue> &proto,
4124514f5e3Sopenharmony_ci                                                      const JSHandle<JSTaggedValue> &baseIhc,
4134514f5e3Sopenharmony_ci                                                      const JSHandle<JSTaggedValue> &transIhc,
4144514f5e3Sopenharmony_ci                                                      const JSHandle<JSTaggedValue> &transPhc)
4154514f5e3Sopenharmony_ci{
4164514f5e3Sopenharmony_ci    JSHandle<JSHClass>::Cast(transIhc)->SetProto(thread, proto.GetTaggedValue());
4174514f5e3Sopenharmony_ci    if (baseIhc.GetTaggedType() == transPhc.GetTaggedType()) {
4184514f5e3Sopenharmony_ci        return;
4194514f5e3Sopenharmony_ci    }
4204514f5e3Sopenharmony_ci    // use transPhc to replace the hclass of proto
4214514f5e3Sopenharmony_ci    JSHandle<JSHClass> oldPhc(thread, proto->GetTaggedObject()->GetClass());
4224514f5e3Sopenharmony_ci    proto->GetTaggedObject()->SynchronizedSetClass(thread, JSHClass::Cast(transPhc->GetTaggedObject()));
4234514f5e3Sopenharmony_ci    ASSERT(JSHClass::Cast(transPhc->GetTaggedObject())->IsPrototype());
4244514f5e3Sopenharmony_ci    // update the prototype of new phc
4254514f5e3Sopenharmony_ci    JSHClass::Cast(transPhc->GetTaggedObject())->SetPrototype(thread, oldPhc->GetPrototype());
4264514f5e3Sopenharmony_ci    // enable prototype change marker
4274514f5e3Sopenharmony_ci    JSTaggedValue phcPrototype = JSHClass::Cast(transPhc->GetTaggedObject())->GetPrototype();
4284514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> parentPrototype(thread, phcPrototype);
4294514f5e3Sopenharmony_ci    ASSERT(parentPrototype->IsECMAObject());
4304514f5e3Sopenharmony_ci    JSHClass::EnablePHCProtoChangeMarker(thread,
4314514f5e3Sopenharmony_ci        JSHandle<JSHClass>(thread, parentPrototype->GetTaggedObject()->GetClass()));
4324514f5e3Sopenharmony_ci    JSHClass::EnableProtoChangeMarker(thread, JSHandle<JSHClass>(transIhc));
4334514f5e3Sopenharmony_ci}
4344514f5e3Sopenharmony_ci
4354514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::CloneWithAddProto(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
4364514f5e3Sopenharmony_ci                                               const JSHandle<JSTaggedValue> &key,
4374514f5e3Sopenharmony_ci                                               const JSHandle<JSTaggedValue> &proto)
4384514f5e3Sopenharmony_ci{
4394514f5e3Sopenharmony_ci    // 1. new a hclass
4404514f5e3Sopenharmony_ci    JSHandle<JSHClass> newJsHClass = JSHClass::Clone(thread, jshclass);
4414514f5e3Sopenharmony_ci    newJsHClass->SetPrototype(thread, proto.GetTaggedValue());
4424514f5e3Sopenharmony_ci
4434514f5e3Sopenharmony_ci    // 2. Add newJsHClass to old jshclass's parent's transitions.
4444514f5e3Sopenharmony_ci    AddProtoTransitions(thread, jshclass, newJsHClass, key, proto);
4454514f5e3Sopenharmony_ci    // parent is the same as jshclass, already copy
4464514f5e3Sopenharmony_ci    return newJsHClass;
4474514f5e3Sopenharmony_ci}
4484514f5e3Sopenharmony_ci
4494514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::TransProtoWithoutLayout(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
4504514f5e3Sopenharmony_ci                                                     const JSHandle<JSTaggedValue> &proto)
4514514f5e3Sopenharmony_ci{
4524514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> key(thread->GlobalConstants()->GetHandledPrototypeString());
4534514f5e3Sopenharmony_ci
4544514f5e3Sopenharmony_ci    {
4554514f5e3Sopenharmony_ci        auto *newClass = jshclass->FindProtoTransitions(key.GetTaggedValue(), proto.GetTaggedValue());
4564514f5e3Sopenharmony_ci        if (newClass != nullptr) {
4574514f5e3Sopenharmony_ci            return JSHandle<JSHClass>(thread, newClass);
4584514f5e3Sopenharmony_ci        }
4594514f5e3Sopenharmony_ci    }
4604514f5e3Sopenharmony_ci
4614514f5e3Sopenharmony_ci    return CloneWithAddProto(thread, jshclass, key, proto);
4624514f5e3Sopenharmony_ci}
4634514f5e3Sopenharmony_ci
4644514f5e3Sopenharmony_civoid JSHClass::SetPrototype(const JSThread *thread, JSTaggedValue proto, bool isChangeProto)
4654514f5e3Sopenharmony_ci{
4664514f5e3Sopenharmony_ci    // Because the heap-space of hclass is non-movable, this function can be non-static.
4674514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> protoHandle(thread, proto);
4684514f5e3Sopenharmony_ci    SetPrototype(thread, protoHandle, isChangeProto);
4694514f5e3Sopenharmony_ci}
4704514f5e3Sopenharmony_ci
4714514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::SetPrototypeWithNotification(const JSThread *thread,
4724514f5e3Sopenharmony_ci                                                          const JSHandle<JSHClass> &hclass,
4734514f5e3Sopenharmony_ci                                                          const JSHandle<JSTaggedValue> &proto,
4744514f5e3Sopenharmony_ci                                                          bool isChangeProto)
4754514f5e3Sopenharmony_ci{
4764514f5e3Sopenharmony_ci    // `hclass` can become prototype inside `TransitionProto` if `hclass` is HClass of `proto`.
4774514f5e3Sopenharmony_ci    // In this case we don't need to notify
4784514f5e3Sopenharmony_ci    auto wasPrototype = hclass->IsPrototype();
4794514f5e3Sopenharmony_ci    JSHandle<JSHClass> newClass = JSHClass::TransitionProto(thread, hclass, proto, isChangeProto);
4804514f5e3Sopenharmony_ci    if (wasPrototype) {
4814514f5e3Sopenharmony_ci        ASSERT(hclass->IsPrototype());
4824514f5e3Sopenharmony_ci        JSHClass::NotifyHclassChanged(thread, hclass, newClass);
4834514f5e3Sopenharmony_ci    }
4844514f5e3Sopenharmony_ci    return newClass;
4854514f5e3Sopenharmony_ci}
4864514f5e3Sopenharmony_ci
4874514f5e3Sopenharmony_civoid JSHClass::SetPrototypeTransition(JSThread *thread, const JSHandle<JSObject> &object,
4884514f5e3Sopenharmony_ci                                      const JSHandle<JSTaggedValue> &proto, bool isChangeProto)
4894514f5e3Sopenharmony_ci{
4904514f5e3Sopenharmony_ci    JSHandle<JSHClass> hclass(thread, object->GetJSHClass());
4914514f5e3Sopenharmony_ci    auto newClass = SetPrototypeWithNotification(thread, hclass, proto, isChangeProto);
4924514f5e3Sopenharmony_ci    RestoreElementsKindToGeneric(*newClass);
4934514f5e3Sopenharmony_ci    object->SynchronizedSetClass(thread, *newClass);
4944514f5e3Sopenharmony_ci    thread->NotifyStableArrayElementsGuardians(object, StableArrayChangeKind::PROTO);
4954514f5e3Sopenharmony_ci    ObjectOperator::UpdateDetectorOnSetPrototype(thread, object.GetTaggedValue());
4964514f5e3Sopenharmony_ci}
4974514f5e3Sopenharmony_ci
4984514f5e3Sopenharmony_civoid JSHClass::SetPrototype(const JSThread *thread, const JSHandle<JSTaggedValue> &proto, bool isChangeProto)
4994514f5e3Sopenharmony_ci{
5004514f5e3Sopenharmony_ci    // Because the heap-space of hclass is non-movable, this function can be non-static.
5014514f5e3Sopenharmony_ci    if (proto->IsJSObject()) {
5024514f5e3Sopenharmony_ci        OptimizePrototypeForIC(thread, proto, isChangeProto);
5034514f5e3Sopenharmony_ci    }
5044514f5e3Sopenharmony_ci    SetProto(thread, proto);
5054514f5e3Sopenharmony_ci}
5064514f5e3Sopenharmony_ci
5074514f5e3Sopenharmony_civoid JSHClass::OptimizePrototypeForIC(const JSThread *thread, const JSHandle<JSTaggedValue> &proto, bool isChangeProto)
5084514f5e3Sopenharmony_ci{
5094514f5e3Sopenharmony_ci    JSHandle<JSHClass> hclass(thread, proto->GetTaggedObject()->GetClass());
5104514f5e3Sopenharmony_ci    ASSERT(!Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(*hclass))->InReadOnlySpace());
5114514f5e3Sopenharmony_ci    if (!hclass->IsPrototype()) {
5124514f5e3Sopenharmony_ci        // Situations for clone proto hclass:
5134514f5e3Sopenharmony_ci        // 1: unshared non-ts hclass
5144514f5e3Sopenharmony_ci        // 2: no matter whether hclass is ts or not when set function prototype
5154514f5e3Sopenharmony_ci        if ((!hclass->IsTS() && !hclass->IsJSShared()) || isChangeProto) {
5164514f5e3Sopenharmony_ci            // The local IC and on-proto IC are different, because the former don't need to notify the whole
5174514f5e3Sopenharmony_ci            // prototype-chain or listen the changes of prototype chain, but the latter do. Therefore, when
5184514f5e3Sopenharmony_ci            // an object becomes a prototype object at the first time, we need to copy its hidden class in
5194514f5e3Sopenharmony_ci            // order to maintain the previously generated local IC and support the on-proto IC in the future.
5204514f5e3Sopenharmony_ci            // For example, a local IC adds a new property x for o1 and the o1.hclass1 -> o1.hclass2, when the
5214514f5e3Sopenharmony_ci            // o1 becomes a prototype object of object o2 and an on-proto IC loading x from o2 will rely on the
5224514f5e3Sopenharmony_ci            // stability of the prototype-chain o2 -> o1. If directly marking the o1.hclass1 as a prototype hclass,
5234514f5e3Sopenharmony_ci            // the previous IC of adding property x won't trigger IC-miss and fails to notify the IC on o2.
5244514f5e3Sopenharmony_ci
5254514f5e3Sopenharmony_ci            // At here, When a JSArray with initial hclass is set as a proto,
5264514f5e3Sopenharmony_ci            // we substitute its hclass with preserved proto hclass.
5274514f5e3Sopenharmony_ci            JSHandle<JSHClass> newProtoClass;
5284514f5e3Sopenharmony_ci            if (ProtoIsFastJSArray(thread, proto, hclass)) {
5294514f5e3Sopenharmony_ci                newProtoClass = JSHandle<JSHClass>(thread, thread->GetArrayInstanceHClass(hclass->GetElementsKind(),
5304514f5e3Sopenharmony_ci                                                                                          true));
5314514f5e3Sopenharmony_ci            } else {
5324514f5e3Sopenharmony_ci                newProtoClass = JSHClass::Clone(thread, hclass);
5334514f5e3Sopenharmony_ci            }
5344514f5e3Sopenharmony_ci            JSTaggedValue layout = newProtoClass->GetLayout();
5354514f5e3Sopenharmony_ci            // If the type of object is JSObject, the layout info value is initialized to the default value,
5364514f5e3Sopenharmony_ci            // if the value is not JSObject, the layout info value is initialized to null.
5374514f5e3Sopenharmony_ci            if (!layout.IsNull()) {
5384514f5e3Sopenharmony_ci                JSMutableHandle<LayoutInfo> layoutInfoHandle(thread, layout);
5394514f5e3Sopenharmony_ci                layoutInfoHandle.Update(
5404514f5e3Sopenharmony_ci                    thread->GetEcmaVM()->GetFactory()->CopyLayoutInfo(layoutInfoHandle).GetTaggedValue());
5414514f5e3Sopenharmony_ci                newProtoClass->SetLayout(thread, layoutInfoHandle);
5424514f5e3Sopenharmony_ci            }
5434514f5e3Sopenharmony_ci
5444514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_IC
5454514f5e3Sopenharmony_ci            // After the hclass is updated, check whether the proto chain status of ic is updated.
5464514f5e3Sopenharmony_ci            NotifyHclassChanged(thread, hclass, newProtoClass);
5474514f5e3Sopenharmony_ci#endif
5484514f5e3Sopenharmony_ci            JSObject::Cast(proto->GetTaggedObject())->SynchronizedSetClass(thread, *newProtoClass);
5494514f5e3Sopenharmony_ci            newProtoClass->SetIsPrototype(true);
5504514f5e3Sopenharmony_ci            // still dump for class in this path now
5514514f5e3Sopenharmony_ci            if (!isChangeProto) {
5524514f5e3Sopenharmony_ci                thread->GetEcmaVM()->GetPGOProfiler()->UpdateRootProfileTypeSafe(*hclass, *newProtoClass);
5534514f5e3Sopenharmony_ci            }
5544514f5e3Sopenharmony_ci        } else {
5554514f5e3Sopenharmony_ci            // There is no sharing in AOT hclass. Therefore, it is not necessary or possible to clone here.
5564514f5e3Sopenharmony_ci            hclass->SetIsPrototype(true);
5574514f5e3Sopenharmony_ci        }
5584514f5e3Sopenharmony_ci    }
5594514f5e3Sopenharmony_ci}
5604514f5e3Sopenharmony_ci
5614514f5e3Sopenharmony_civoid JSHClass::TransitionToDictionary(const JSThread *thread, const JSHandle<JSObject> &obj)
5624514f5e3Sopenharmony_ci{
5634514f5e3Sopenharmony_ci    // 1. new a hclass
5644514f5e3Sopenharmony_ci    JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
5654514f5e3Sopenharmony_ci    JSHandle<JSHClass> newJsHClass = CloneWithoutInlinedProperties(thread, jshclass);
5664514f5e3Sopenharmony_ci
5674514f5e3Sopenharmony_ci    {
5684514f5e3Sopenharmony_ci        DISALLOW_GARBAGE_COLLECTION;
5694514f5e3Sopenharmony_ci        // 2. Copy
5704514f5e3Sopenharmony_ci        newJsHClass->SetNumberOfProps(0);
5714514f5e3Sopenharmony_ci        newJsHClass->SetIsDictionaryMode(true);
5724514f5e3Sopenharmony_ci        ASSERT(newJsHClass->GetInlinedProperties() == 0);
5734514f5e3Sopenharmony_ci
5744514f5e3Sopenharmony_ci        // 3. Add newJsHClass to ?
5754514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_IC
5764514f5e3Sopenharmony_ci        JSHClass::NotifyHclassChanged(thread, JSHandle<JSHClass>(thread, obj->GetJSHClass()), newJsHClass);
5774514f5e3Sopenharmony_ci#endif
5784514f5e3Sopenharmony_ci        RestoreElementsKindToGeneric(*newJsHClass);
5794514f5e3Sopenharmony_ci        obj->SynchronizedSetClass(thread, *newJsHClass);
5804514f5e3Sopenharmony_ci    }
5814514f5e3Sopenharmony_ci}
5824514f5e3Sopenharmony_ci
5834514f5e3Sopenharmony_civoid JSHClass::OptimizeAsFastProperties(const JSThread *thread, const JSHandle<JSObject> &obj,
5844514f5e3Sopenharmony_ci                                        const std::vector<int> &indexOrder, bool isDictionary)
5854514f5e3Sopenharmony_ci{
5864514f5e3Sopenharmony_ci    // 1. new a hclass
5874514f5e3Sopenharmony_ci    JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
5884514f5e3Sopenharmony_ci    JSHandle<JSHClass> newJsHClass = Clone(thread, jshclass, isDictionary);
5894514f5e3Sopenharmony_ci
5904514f5e3Sopenharmony_ci    // 2. If it is dictionary, migrate should change layout. otherwise, copy the hclass only.
5914514f5e3Sopenharmony_ci    if (isDictionary) {
5924514f5e3Sopenharmony_ci        JSHandle<NameDictionary> properties(thread, obj->GetProperties());
5934514f5e3Sopenharmony_ci        int numberOfProperties = properties->EntriesCount();
5944514f5e3Sopenharmony_ci        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
5954514f5e3Sopenharmony_ci        JSHandle<LayoutInfo> layoutInfoHandle = factory->CreateLayoutInfo(numberOfProperties);
5964514f5e3Sopenharmony_ci        int numberOfInlinedProps = static_cast<int>(newJsHClass->GetInlinedProperties());
5974514f5e3Sopenharmony_ci        for (int i = 0; i < numberOfProperties; i++) {
5984514f5e3Sopenharmony_ci            JSTaggedValue key = properties->GetKey(indexOrder[i]);
5994514f5e3Sopenharmony_ci            PropertyAttributes attributes = properties->GetAttributes(indexOrder[i]);
6004514f5e3Sopenharmony_ci            if (i < numberOfInlinedProps) {
6014514f5e3Sopenharmony_ci                attributes.SetIsInlinedProps(true);
6024514f5e3Sopenharmony_ci            } else {
6034514f5e3Sopenharmony_ci                attributes.SetIsInlinedProps(false);
6044514f5e3Sopenharmony_ci            }
6054514f5e3Sopenharmony_ci            attributes.SetOffset(i);
6064514f5e3Sopenharmony_ci            layoutInfoHandle->AddKey(thread, i, key, attributes);
6074514f5e3Sopenharmony_ci        }
6084514f5e3Sopenharmony_ci
6094514f5e3Sopenharmony_ci        {
6104514f5e3Sopenharmony_ci            DISALLOW_GARBAGE_COLLECTION;
6114514f5e3Sopenharmony_ci            newJsHClass->SetNumberOfProps(numberOfProperties);
6124514f5e3Sopenharmony_ci            newJsHClass->SetLayout(thread, layoutInfoHandle);
6134514f5e3Sopenharmony_ci        }
6144514f5e3Sopenharmony_ci    }
6154514f5e3Sopenharmony_ci
6164514f5e3Sopenharmony_ci    {
6174514f5e3Sopenharmony_ci        DISALLOW_GARBAGE_COLLECTION;
6184514f5e3Sopenharmony_ci        // 3. Copy
6194514f5e3Sopenharmony_ci        newJsHClass->SetIsDictionaryMode(false);
6204514f5e3Sopenharmony_ci        // 4. Add newJsHClass to ?
6214514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_IC
6224514f5e3Sopenharmony_ci        JSHClass::NotifyHclassChanged(thread, JSHandle<JSHClass>(thread, obj->GetJSHClass()), newJsHClass);
6234514f5e3Sopenharmony_ci#endif
6244514f5e3Sopenharmony_ci        obj->SynchronizedSetClass(thread, *newJsHClass);
6254514f5e3Sopenharmony_ci    }
6264514f5e3Sopenharmony_ci}
6274514f5e3Sopenharmony_ci
6284514f5e3Sopenharmony_civoid JSHClass::TransitionForRepChange(const JSThread *thread, const JSHandle<JSObject> &receiver,
6294514f5e3Sopenharmony_ci    const JSHandle<JSTaggedValue> &key, PropertyAttributes attr)
6304514f5e3Sopenharmony_ci{
6314514f5e3Sopenharmony_ci    JSHandle<JSHClass> oldHClass(thread, receiver->GetJSHClass());
6324514f5e3Sopenharmony_ci
6334514f5e3Sopenharmony_ci    // 1. Create hclass and copy layout
6344514f5e3Sopenharmony_ci    JSHandle<JSHClass> newHClass = JSHClass::Clone(thread, oldHClass);
6354514f5e3Sopenharmony_ci    RestoreElementsKindToGeneric(*newHClass);
6364514f5e3Sopenharmony_ci
6374514f5e3Sopenharmony_ci    JSHandle<LayoutInfo> oldLayout(thread, newHClass->GetLayout());
6384514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
6394514f5e3Sopenharmony_ci    JSHandle<LayoutInfo> newLayout(factory->CopyLayoutInfo(oldLayout));
6404514f5e3Sopenharmony_ci    newHClass->SetLayout(thread, newLayout);
6414514f5e3Sopenharmony_ci
6424514f5e3Sopenharmony_ci    // 2. update attr
6434514f5e3Sopenharmony_ci    auto hclass = JSHClass::Cast(newHClass.GetTaggedValue().GetTaggedObject());
6444514f5e3Sopenharmony_ci    int entry = JSHClass::FindPropertyEntry(thread, hclass, key.GetTaggedValue());
6454514f5e3Sopenharmony_ci    ASSERT(entry != -1);
6464514f5e3Sopenharmony_ci    newLayout->SetNormalAttr(thread, entry, attr);
6474514f5e3Sopenharmony_ci
6484514f5e3Sopenharmony_ci    // 3. update hclass in object.
6494514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_IC
6504514f5e3Sopenharmony_ci    JSHClass::NotifyHclassChanged(thread, oldHClass, newHClass, key.GetTaggedValue());
6514514f5e3Sopenharmony_ci#endif
6524514f5e3Sopenharmony_ci
6534514f5e3Sopenharmony_ci    receiver->SynchronizedSetClass(thread, *newHClass);
6544514f5e3Sopenharmony_ci    // 4. Maybe Transition And Maintain subtypeing check
6554514f5e3Sopenharmony_ci}
6564514f5e3Sopenharmony_ci
6574514f5e3Sopenharmony_cibool JSHClass::IsInitialArrayHClassWithElementsKind(const JSThread *thread, const JSHClass *targetHClass,
6584514f5e3Sopenharmony_ci                                                    const ElementsKind targetKind)
6594514f5e3Sopenharmony_ci{
6604514f5e3Sopenharmony_ci    const auto &arrayHClassIndexMap = thread->GetArrayHClassIndexMap();
6614514f5e3Sopenharmony_ci    auto newKindIter = arrayHClassIndexMap.find(targetKind);
6624514f5e3Sopenharmony_ci    if (newKindIter != arrayHClassIndexMap.end()) {
6634514f5e3Sopenharmony_ci        auto indexPair = newKindIter->second;
6644514f5e3Sopenharmony_ci        auto hclassVal = thread->GlobalConstants()->GetGlobalConstantObject(static_cast<size_t>(indexPair.first));
6654514f5e3Sopenharmony_ci        auto hclassWithProtoVal = thread->GlobalConstants()->
6664514f5e3Sopenharmony_ci            GetGlobalConstantObject(static_cast<size_t>(indexPair.second));
6674514f5e3Sopenharmony_ci        JSHClass *hclass = JSHClass::Cast(hclassVal.GetTaggedObject());
6684514f5e3Sopenharmony_ci        JSHClass *hclassWithProto = JSHClass::Cast(hclassWithProtoVal.GetTaggedObject());
6694514f5e3Sopenharmony_ci        return (targetHClass == hclass || targetHClass == hclassWithProto);
6704514f5e3Sopenharmony_ci    }
6714514f5e3Sopenharmony_ci    return false;
6724514f5e3Sopenharmony_ci}
6734514f5e3Sopenharmony_ci
6744514f5e3Sopenharmony_cibool JSHClass::TransitToElementsKindUncheck(const JSThread *thread, const JSHandle<JSObject> &obj,
6754514f5e3Sopenharmony_ci                                            ElementsKind newKind)
6764514f5e3Sopenharmony_ci{
6774514f5e3Sopenharmony_ci    ElementsKind current = obj->GetJSHClass()->GetElementsKind();
6784514f5e3Sopenharmony_ci    // currently we only support initial array hclass
6794514f5e3Sopenharmony_ci    JSHClass *objHclass = obj->GetClass();
6804514f5e3Sopenharmony_ci    if (IsInitialArrayHClassWithElementsKind(thread, objHclass, current)) {
6814514f5e3Sopenharmony_ci        const auto &arrayHClassIndexMap = thread->GetArrayHClassIndexMap();
6824514f5e3Sopenharmony_ci        auto newKindIter = arrayHClassIndexMap.find(newKind);
6834514f5e3Sopenharmony_ci        bool objHclassIsPrototype = objHclass->IsPrototype();
6844514f5e3Sopenharmony_ci        if (newKindIter != arrayHClassIndexMap.end()) {
6854514f5e3Sopenharmony_ci            auto indexPair = newKindIter->second;
6864514f5e3Sopenharmony_ci            auto index = objHclassIsPrototype ? static_cast<size_t>(indexPair.second) :
6874514f5e3Sopenharmony_ci                                                static_cast<size_t>(indexPair.first);
6884514f5e3Sopenharmony_ci            auto hclassVal = thread->GlobalConstants()->GetGlobalConstantObject(index);
6894514f5e3Sopenharmony_ci            JSHClass *hclass = JSHClass::Cast(hclassVal.GetTaggedObject());
6904514f5e3Sopenharmony_ci            obj->SynchronizedSetClass(thread, hclass);
6914514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_IC
6924514f5e3Sopenharmony_ci            JSHClass::NotifyHclassChanged(thread, JSHandle<JSHClass>(thread, objHclass),
6934514f5e3Sopenharmony_ci                                          JSHandle<JSHClass>(thread, hclass));
6944514f5e3Sopenharmony_ci#endif
6954514f5e3Sopenharmony_ci            return true;
6964514f5e3Sopenharmony_ci        }
6974514f5e3Sopenharmony_ci        LOG_ECMA(FATAL) << "Unknown newKind: " << static_cast<int32_t>(newKind);
6984514f5e3Sopenharmony_ci    }
6994514f5e3Sopenharmony_ci    return false;
7004514f5e3Sopenharmony_ci}
7014514f5e3Sopenharmony_ci
7024514f5e3Sopenharmony_civoid JSHClass::TransitToElementsKind(const JSThread *thread, const JSHandle<JSArray> &array,
7034514f5e3Sopenharmony_ci                                     ElementsKind newKind)
7044514f5e3Sopenharmony_ci{
7054514f5e3Sopenharmony_ci    JSTaggedValue elements = array->GetElements();
7064514f5e3Sopenharmony_ci    if (!elements.IsTaggedArray()) {
7074514f5e3Sopenharmony_ci        return;
7084514f5e3Sopenharmony_ci    }
7094514f5e3Sopenharmony_ci    ElementsKind current = array->GetJSHClass()->GetElementsKind();
7104514f5e3Sopenharmony_ci    newKind = Elements::MergeElementsKind(newKind, current);
7114514f5e3Sopenharmony_ci    if (newKind == current) {
7124514f5e3Sopenharmony_ci        return;
7134514f5e3Sopenharmony_ci    }
7144514f5e3Sopenharmony_ci
7154514f5e3Sopenharmony_ci    ASSERT(IsInitialArrayHClassWithElementsKind(thread, array->GetJSHClass(), current));
7164514f5e3Sopenharmony_ci    TransitToElementsKindUncheck(thread, JSHandle<JSObject>(array), newKind);
7174514f5e3Sopenharmony_ci}
7184514f5e3Sopenharmony_ci
7194514f5e3Sopenharmony_cibool JSHClass::TransitToElementsKind(const JSThread *thread, const JSHandle<JSObject> &object,
7204514f5e3Sopenharmony_ci                                     const JSHandle<JSTaggedValue> &value, ElementsKind kind)
7214514f5e3Sopenharmony_ci{
7224514f5e3Sopenharmony_ci    if (!object->IsJSArray()) {
7234514f5e3Sopenharmony_ci        return false;
7244514f5e3Sopenharmony_ci    }
7254514f5e3Sopenharmony_ci    ElementsKind current = object->GetJSHClass()->GetElementsKind();
7264514f5e3Sopenharmony_ci    if (Elements::IsGeneric(current)) {
7274514f5e3Sopenharmony_ci        return false;
7284514f5e3Sopenharmony_ci    }
7294514f5e3Sopenharmony_ci    auto newKind = Elements::ToElementsKind(value.GetTaggedValue(), kind);
7304514f5e3Sopenharmony_ci    // Merge current kind and new kind
7314514f5e3Sopenharmony_ci    newKind = Elements::MergeElementsKind(current, newKind);
7324514f5e3Sopenharmony_ci    if (newKind == current) {
7334514f5e3Sopenharmony_ci        return false;
7344514f5e3Sopenharmony_ci    }
7354514f5e3Sopenharmony_ci    // Currently, we only support fast array elementsKind
7364514f5e3Sopenharmony_ci    ASSERT(IsInitialArrayHClassWithElementsKind(thread, object->GetJSHClass(), current));
7374514f5e3Sopenharmony_ci    if (!TransitToElementsKindUncheck(thread, object, newKind)) {
7384514f5e3Sopenharmony_ci        return false;
7394514f5e3Sopenharmony_ci    }
7404514f5e3Sopenharmony_ci
7414514f5e3Sopenharmony_ci    if (!thread->GetEcmaVM()->IsEnableElementsKind()) {
7424514f5e3Sopenharmony_ci        // Update TrackInfo
7434514f5e3Sopenharmony_ci        if (!thread->IsPGOProfilerEnable()) {
7444514f5e3Sopenharmony_ci            return true;
7454514f5e3Sopenharmony_ci        }
7464514f5e3Sopenharmony_ci        auto trackInfoVal = JSHandle<JSArray>(object)->GetTrackInfo();
7474514f5e3Sopenharmony_ci        thread->GetEcmaVM()->GetPGOProfiler()->UpdateTrackElementsKind(trackInfoVal, newKind);
7484514f5e3Sopenharmony_ci        return true;
7494514f5e3Sopenharmony_ci    }
7504514f5e3Sopenharmony_ci    return true;
7514514f5e3Sopenharmony_ci}
7524514f5e3Sopenharmony_ci
7534514f5e3Sopenharmony_civoid JSHClass::UpdateFieldType(JSHClass *hclass, const PropertyAttributes &attr)
7544514f5e3Sopenharmony_ci{
7554514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
7564514f5e3Sopenharmony_ci    JSHClass *ownHClass = FindFieldOwnHClass(hclass, attr);
7574514f5e3Sopenharmony_ci    VisitAndUpdateLayout(ownHClass, attr);
7584514f5e3Sopenharmony_ci}
7594514f5e3Sopenharmony_ci
7604514f5e3Sopenharmony_ciJSHClass *JSHClass::FindFieldOwnHClass(JSHClass *hclass, const PropertyAttributes &attr)
7614514f5e3Sopenharmony_ci{
7624514f5e3Sopenharmony_ci    uint32_t offset = attr.GetOffset();
7634514f5e3Sopenharmony_ci    JSTaggedValue parent(hclass);
7644514f5e3Sopenharmony_ci    JSHClass *curHClass = hclass;
7654514f5e3Sopenharmony_ci    while (parent.IsJSHClass()) {
7664514f5e3Sopenharmony_ci        auto parentHClass = JSHClass::Cast(parent.GetTaggedObject());
7674514f5e3Sopenharmony_ci        if (parentHClass->NumberOfProps() <= offset) {
7684514f5e3Sopenharmony_ci            break;
7694514f5e3Sopenharmony_ci        }
7704514f5e3Sopenharmony_ci        curHClass = parentHClass;
7714514f5e3Sopenharmony_ci        parent = curHClass->GetParent();
7724514f5e3Sopenharmony_ci    }
7734514f5e3Sopenharmony_ci    return curHClass;
7744514f5e3Sopenharmony_ci}
7754514f5e3Sopenharmony_ci
7764514f5e3Sopenharmony_civoid JSHClass::VisitAndUpdateLayout(JSHClass *ownHClass, const PropertyAttributes &attr)
7774514f5e3Sopenharmony_ci{
7784514f5e3Sopenharmony_ci    uint32_t offset = attr.GetOffset();
7794514f5e3Sopenharmony_ci    auto targetTrackType = attr.GetTrackType();
7804514f5e3Sopenharmony_ci    std::queue<JSHClass *> backHClass;
7814514f5e3Sopenharmony_ci    backHClass.push(ownHClass);
7824514f5e3Sopenharmony_ci    while (!backHClass.empty()) {
7834514f5e3Sopenharmony_ci        JSHClass *current = backHClass.front();
7844514f5e3Sopenharmony_ci        backHClass.pop();
7854514f5e3Sopenharmony_ci
7864514f5e3Sopenharmony_ci        auto layout = LayoutInfo::Cast(current->GetLayout().GetTaggedObject());
7874514f5e3Sopenharmony_ci        if (layout->GetAttr(offset).GetTrackType() != targetTrackType) {
7884514f5e3Sopenharmony_ci            layout->UpdateTrackTypeAttr(offset, attr);
7894514f5e3Sopenharmony_ci        }
7904514f5e3Sopenharmony_ci
7914514f5e3Sopenharmony_ci        auto transitions = current->GetTransitions();
7924514f5e3Sopenharmony_ci        if (transitions.IsUndefined()) {
7934514f5e3Sopenharmony_ci            continue;
7944514f5e3Sopenharmony_ci        }
7954514f5e3Sopenharmony_ci        if (transitions.IsWeak()) {
7964514f5e3Sopenharmony_ci            auto cache = transitions.GetTaggedWeakRef();
7974514f5e3Sopenharmony_ci            backHClass.push(JSHClass::Cast(cache));
7984514f5e3Sopenharmony_ci            continue;
7994514f5e3Sopenharmony_ci        }
8004514f5e3Sopenharmony_ci
8014514f5e3Sopenharmony_ci        ASSERT(transitions.IsTaggedArray());
8024514f5e3Sopenharmony_ci        TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject());
8034514f5e3Sopenharmony_ci        dict->IterateEntryValue([&backHClass] (JSHClass *cache) {
8044514f5e3Sopenharmony_ci            backHClass.push(JSHClass::Cast(cache));
8054514f5e3Sopenharmony_ci        });
8064514f5e3Sopenharmony_ci    }
8074514f5e3Sopenharmony_ci}
8084514f5e3Sopenharmony_ci
8094514f5e3Sopenharmony_ciTransitionResult JSHClass::ConvertOrTransitionWithRep(const JSThread *thread,
8104514f5e3Sopenharmony_ci    const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
8114514f5e3Sopenharmony_ci    PropertyAttributes &attr)
8124514f5e3Sopenharmony_ci{
8134514f5e3Sopenharmony_ci    auto hclass = receiver->GetJSHClass();
8144514f5e3Sopenharmony_ci    auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
8154514f5e3Sopenharmony_ci    attr = layout->GetAttr(attr.GetOffset());
8164514f5e3Sopenharmony_ci    if (thread->IsPGOProfilerEnable() && !hclass->IsJSShared() && attr.UpdateTrackType(value.GetTaggedValue())) {
8174514f5e3Sopenharmony_ci        UpdateFieldType(hclass, attr);
8184514f5e3Sopenharmony_ci    }
8194514f5e3Sopenharmony_ci
8204514f5e3Sopenharmony_ci    Representation oldRep = attr.GetRepresentation();
8214514f5e3Sopenharmony_ci    if (oldRep == Representation::DOUBLE) {
8224514f5e3Sopenharmony_ci        if (value->IsInt()) {
8234514f5e3Sopenharmony_ci            double doubleValue = value->GetInt();
8244514f5e3Sopenharmony_ci            return {false, false, JSTaggedValue(bit_cast<JSTaggedType>(doubleValue))};
8254514f5e3Sopenharmony_ci        } else if (value->IsObject()) {
8264514f5e3Sopenharmony_ci            // Is Object
8274514f5e3Sopenharmony_ci            attr.SetRepresentation(Representation::TAGGED);
8284514f5e3Sopenharmony_ci            // Transition
8294514f5e3Sopenharmony_ci            JSHClass::TransitionForRepChange(thread, receiver, key, attr);
8304514f5e3Sopenharmony_ci            return {true, true, value.GetTaggedValue()};
8314514f5e3Sopenharmony_ci        } else {
8324514f5e3Sopenharmony_ci            // Is TaggedDouble
8334514f5e3Sopenharmony_ci            return {false, false, JSTaggedValue(bit_cast<JSTaggedType>(value->GetDouble()))};
8344514f5e3Sopenharmony_ci        }
8354514f5e3Sopenharmony_ci    } else if (oldRep == Representation::INT) {
8364514f5e3Sopenharmony_ci        if (value->IsInt()) {
8374514f5e3Sopenharmony_ci            int intValue = value->GetInt();
8384514f5e3Sopenharmony_ci            return {false, false, JSTaggedValue(static_cast<JSTaggedType>(intValue))};
8394514f5e3Sopenharmony_ci        } else {
8404514f5e3Sopenharmony_ci            attr.SetRepresentation(Representation::TAGGED);
8414514f5e3Sopenharmony_ci            JSHClass::TransitionForRepChange(thread, receiver, key, attr);
8424514f5e3Sopenharmony_ci            return {true, true, value.GetTaggedValue()};
8434514f5e3Sopenharmony_ci        }
8444514f5e3Sopenharmony_ci    }
8454514f5e3Sopenharmony_ci    return {true, false, value.GetTaggedValue()};
8464514f5e3Sopenharmony_ci}
8474514f5e3Sopenharmony_ci
8484514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSHClass::EnableProtoChangeMarker(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
8494514f5e3Sopenharmony_ci{
8504514f5e3Sopenharmony_ci    JSTaggedValue proto = jshclass->GetPrototype();
8514514f5e3Sopenharmony_ci    if (!proto.IsECMAObject()) {
8524514f5e3Sopenharmony_ci        // Return JSTaggedValue directly. No proto check is needed.
8534514f5e3Sopenharmony_ci        LOG_ECMA(INFO) << "proto is not ecmaobject: " << proto.GetRawData();
8544514f5e3Sopenharmony_ci        return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Null());
8554514f5e3Sopenharmony_ci    }
8564514f5e3Sopenharmony_ci    JSHandle<JSObject> protoHandle(thread, proto);
8574514f5e3Sopenharmony_ci    JSHandle<JSHClass> protoClass(thread, protoHandle->GetJSHClass());
8584514f5e3Sopenharmony_ci    // in AOT's IC mechanism (VTable), when the prototype chain changes, it needs to notify each subclass
8594514f5e3Sopenharmony_ci    // PHC (prototype-HClass) and its IHC (instance-HClass) from the current PHC along the chain.
8604514f5e3Sopenharmony_ci    // therefore, when registering, it is also necessary to register IHC into its
8614514f5e3Sopenharmony_ci    // PHC's Listener to ensure that it can be notified.
8624514f5e3Sopenharmony_ci    RegisterOnProtoChain(thread, protoClass);
8634514f5e3Sopenharmony_ci
8644514f5e3Sopenharmony_ci    JSTaggedValue protoChangeMarker = protoClass->GetProtoChangeMarker();
8654514f5e3Sopenharmony_ci    if (protoChangeMarker.IsProtoChangeMarker()) {
8664514f5e3Sopenharmony_ci        JSHandle<ProtoChangeMarker> markerHandle(thread, ProtoChangeMarker::Cast(protoChangeMarker.GetTaggedObject()));
8674514f5e3Sopenharmony_ci        if (!markerHandle->GetHasChanged()) {
8684514f5e3Sopenharmony_ci            return JSHandle<JSTaggedValue>(markerHandle);
8694514f5e3Sopenharmony_ci        }
8704514f5e3Sopenharmony_ci    }
8714514f5e3Sopenharmony_ci    JSHandle<ProtoChangeMarker> markerHandle = thread->GetEcmaVM()->GetFactory()->NewProtoChangeMarker();
8724514f5e3Sopenharmony_ci    markerHandle->SetHasChanged(false);
8734514f5e3Sopenharmony_ci    // ShareToLocal is prohibited
8744514f5e3Sopenharmony_ci    if (!protoClass->IsJSShared()) {
8754514f5e3Sopenharmony_ci        protoClass->SetProtoChangeMarker(thread, markerHandle.GetTaggedValue());
8764514f5e3Sopenharmony_ci    }
8774514f5e3Sopenharmony_ci    return JSHandle<JSTaggedValue>(markerHandle);
8784514f5e3Sopenharmony_ci}
8794514f5e3Sopenharmony_ci
8804514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSHClass::EnablePHCProtoChangeMarker(const JSThread *thread,
8814514f5e3Sopenharmony_ci    const JSHandle<JSHClass> &protoClass)
8824514f5e3Sopenharmony_ci{
8834514f5e3Sopenharmony_ci    RegisterOnProtoChain(thread, protoClass);
8844514f5e3Sopenharmony_ci
8854514f5e3Sopenharmony_ci    JSTaggedValue protoChangeMarker = protoClass->GetProtoChangeMarker();
8864514f5e3Sopenharmony_ci    if (protoChangeMarker.IsProtoChangeMarker()) {
8874514f5e3Sopenharmony_ci        JSHandle<ProtoChangeMarker> markerHandle(thread, ProtoChangeMarker::Cast(protoChangeMarker.GetTaggedObject()));
8884514f5e3Sopenharmony_ci        if (!markerHandle->GetHasChanged()) {
8894514f5e3Sopenharmony_ci            return JSHandle<JSTaggedValue>(markerHandle);
8904514f5e3Sopenharmony_ci        }
8914514f5e3Sopenharmony_ci    }
8924514f5e3Sopenharmony_ci    JSHandle<ProtoChangeMarker> markerHandle = thread->GetEcmaVM()->GetFactory()->NewProtoChangeMarker();
8934514f5e3Sopenharmony_ci    markerHandle->SetHasChanged(false);
8944514f5e3Sopenharmony_ci    protoClass->SetProtoChangeMarker(thread, markerHandle.GetTaggedValue());
8954514f5e3Sopenharmony_ci    return JSHandle<JSTaggedValue>(markerHandle);
8964514f5e3Sopenharmony_ci}
8974514f5e3Sopenharmony_ci
8984514f5e3Sopenharmony_civoid JSHClass::NotifyHclassChanged(const JSThread *thread, JSHandle<JSHClass> oldHclass, JSHandle<JSHClass> newHclass,
8994514f5e3Sopenharmony_ci                                   JSTaggedValue addedKey)
9004514f5e3Sopenharmony_ci{
9014514f5e3Sopenharmony_ci    if (!oldHclass->IsPrototype()) {
9024514f5e3Sopenharmony_ci        return;
9034514f5e3Sopenharmony_ci    }
9044514f5e3Sopenharmony_ci    // The old hclass is the same as new one
9054514f5e3Sopenharmony_ci    if (oldHclass.GetTaggedValue() == newHclass.GetTaggedValue()) {
9064514f5e3Sopenharmony_ci        return;
9074514f5e3Sopenharmony_ci    }
9084514f5e3Sopenharmony_ci    // For now, at pgo profiling stage, we use ProfileType::Kind to mark a hclass is CHC, PHC or IHC.
9094514f5e3Sopenharmony_ci    // We can have case like the following:
9104514f5e3Sopenharmony_ci    //
9114514f5e3Sopenharmony_ci    //     class C3 {
9124514f5e3Sopenharmony_ci    //         constructor(a5) {
9134514f5e3Sopenharmony_ci    //         }
9144514f5e3Sopenharmony_ci    //     }
9154514f5e3Sopenharmony_ci    //     class C18 extends C3 {
9164514f5e3Sopenharmony_ci    //         constructor() {
9174514f5e3Sopenharmony_ci    //             super(1);
9184514f5e3Sopenharmony_ci    //             C3.valueOf = 1;
9194514f5e3Sopenharmony_ci    //         }
9204514f5e3Sopenharmony_ci    //     }
9214514f5e3Sopenharmony_ci    //     const v37 = new C18();
9224514f5e3Sopenharmony_ci    //
9234514f5e3Sopenharmony_ci    // C3 is profiled as CHC even though its IsPrototype bit is marked as true when 'class C18 extends C3' is executed.
9244514f5e3Sopenharmony_ci    // Since C3 is marked as CHC and it has ProfileType::Kind::ConstructorId,
9254514f5e3Sopenharmony_ci    // when generating hclass at aot, its child hclass and itself will not have IsPrototype bit set as true.
9264514f5e3Sopenharmony_ci    //
9274514f5e3Sopenharmony_ci    // However, we currently support hclass substitution when executing 'C3.valueOf' for C3's oldHclass at runtime.
9284514f5e3Sopenharmony_ci    // Therefore, oldHclass's IsPrototype bit is set as true; But for newHclass, it is generated at aot stage,
9294514f5e3Sopenharmony_ci    // it will not have IsPrototype bit set as true.
9304514f5e3Sopenharmony_ci    //
9314514f5e3Sopenharmony_ci    // Good neww is our AOT hclass can not be shared, hence we can set newHclass IsPrototype as true at here.
9324514f5e3Sopenharmony_ci    if (newHclass->IsTS() && !newHclass->IsPrototype()) {
9334514f5e3Sopenharmony_ci        newHclass->SetIsPrototype(true);
9344514f5e3Sopenharmony_ci    }
9354514f5e3Sopenharmony_ci    JSHClass::NoticeThroughChain(thread, oldHclass, addedKey);
9364514f5e3Sopenharmony_ci    JSHClass::RefreshUsers(thread, oldHclass, newHclass);
9374514f5e3Sopenharmony_ci}
9384514f5e3Sopenharmony_ci
9394514f5e3Sopenharmony_civoid JSHClass::NotifyAccessorChanged(const JSThread *thread, JSHandle<JSHClass> hclass)
9404514f5e3Sopenharmony_ci{
9414514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
9424514f5e3Sopenharmony_ci    JSTaggedValue markerValue = hclass->GetProtoChangeMarker();
9434514f5e3Sopenharmony_ci    if (markerValue.IsProtoChangeMarker()) {
9444514f5e3Sopenharmony_ci        ProtoChangeMarker *protoChangeMarker = ProtoChangeMarker::Cast(markerValue.GetTaggedObject());
9454514f5e3Sopenharmony_ci        protoChangeMarker->SetAccessorHasChanged(true);
9464514f5e3Sopenharmony_ci    }
9474514f5e3Sopenharmony_ci
9484514f5e3Sopenharmony_ci    JSTaggedValue protoDetailsValue = hclass->GetProtoChangeDetails();
9494514f5e3Sopenharmony_ci    if (!protoDetailsValue.IsProtoChangeDetails()) {
9504514f5e3Sopenharmony_ci        return;
9514514f5e3Sopenharmony_ci    }
9524514f5e3Sopenharmony_ci    JSTaggedValue listenersValue = ProtoChangeDetails::Cast(protoDetailsValue.GetTaggedObject())->GetChangeListener();
9534514f5e3Sopenharmony_ci    if (!listenersValue.IsTaggedArray()) {
9544514f5e3Sopenharmony_ci        return;
9554514f5e3Sopenharmony_ci    }
9564514f5e3Sopenharmony_ci    ChangeListener *listeners = ChangeListener::Cast(listenersValue.GetTaggedObject());
9574514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < listeners->GetEnd(); i++) {
9584514f5e3Sopenharmony_ci        JSTaggedValue temp = listeners->Get(i);
9594514f5e3Sopenharmony_ci        if (temp.IsJSHClass()) {
9604514f5e3Sopenharmony_ci            NotifyAccessorChanged(thread, JSHandle<JSHClass>(thread, listeners->Get(i).GetTaggedObject()));
9614514f5e3Sopenharmony_ci        }
9624514f5e3Sopenharmony_ci    }
9634514f5e3Sopenharmony_ci}
9644514f5e3Sopenharmony_ci
9654514f5e3Sopenharmony_civoid JSHClass::RegisterOnProtoChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
9664514f5e3Sopenharmony_ci{
9674514f5e3Sopenharmony_ci    // ShareToLocal is prohibited
9684514f5e3Sopenharmony_ci    if (jshclass->IsJSShared()) {
9694514f5e3Sopenharmony_ci        return;
9704514f5e3Sopenharmony_ci    }
9714514f5e3Sopenharmony_ci    JSHandle<JSHClass> user = jshclass;
9724514f5e3Sopenharmony_ci    JSHandle<ProtoChangeDetails> userDetails = GetProtoChangeDetails(thread, user);
9734514f5e3Sopenharmony_ci
9744514f5e3Sopenharmony_ci    while (true) {
9754514f5e3Sopenharmony_ci        // Find the prototype chain as far as the hclass has not been registered.
9764514f5e3Sopenharmony_ci        if (userDetails->GetRegisterIndex() != static_cast<uint32_t>(ProtoChangeDetails::UNREGISTERED)) {
9774514f5e3Sopenharmony_ci            return;
9784514f5e3Sopenharmony_ci        }
9794514f5e3Sopenharmony_ci
9804514f5e3Sopenharmony_ci        JSTaggedValue proto = user->GetPrototype();
9814514f5e3Sopenharmony_ci        if (!proto.IsHeapObject()) {
9824514f5e3Sopenharmony_ci            return;
9834514f5e3Sopenharmony_ci        }
9844514f5e3Sopenharmony_ci        if (proto.IsJSProxy()) {
9854514f5e3Sopenharmony_ci            return;
9864514f5e3Sopenharmony_ci        }
9874514f5e3Sopenharmony_ci        // ShareToLocal is prohibited
9884514f5e3Sopenharmony_ci        if (proto.IsJSShared()) {
9894514f5e3Sopenharmony_ci            return;
9904514f5e3Sopenharmony_ci        }
9914514f5e3Sopenharmony_ci        ASSERT(proto.IsECMAObject());
9924514f5e3Sopenharmony_ci        JSHandle<JSObject> protoHandle(thread, proto);
9934514f5e3Sopenharmony_ci        JSHandle<ProtoChangeDetails> protoDetails =
9944514f5e3Sopenharmony_ci            GetProtoChangeDetails(thread, JSHandle<JSHClass>(thread, protoHandle->GetJSHClass()));
9954514f5e3Sopenharmony_ci        JSTaggedValue listeners = protoDetails->GetChangeListener();
9964514f5e3Sopenharmony_ci        JSHandle<ChangeListener> listenersHandle;
9974514f5e3Sopenharmony_ci        if (listeners.IsUndefined()) {
9984514f5e3Sopenharmony_ci            listenersHandle = JSHandle<ChangeListener>(ChangeListener::Create(thread));
9994514f5e3Sopenharmony_ci        } else {
10004514f5e3Sopenharmony_ci            listenersHandle = JSHandle<ChangeListener>(thread, listeners);
10014514f5e3Sopenharmony_ci        }
10024514f5e3Sopenharmony_ci        uint32_t registerIndex = 0;
10034514f5e3Sopenharmony_ci        JSHandle<ChangeListener> newListeners = ChangeListener::Add(thread, listenersHandle, user, &registerIndex);
10044514f5e3Sopenharmony_ci        userDetails->SetRegisterIndex(registerIndex);
10054514f5e3Sopenharmony_ci        protoDetails->SetChangeListener(thread, newListeners.GetTaggedValue());
10064514f5e3Sopenharmony_ci        userDetails = protoDetails;
10074514f5e3Sopenharmony_ci        user = JSHandle<JSHClass>(thread, protoHandle->GetJSHClass());
10084514f5e3Sopenharmony_ci    }
10094514f5e3Sopenharmony_ci}
10104514f5e3Sopenharmony_ci
10114514f5e3Sopenharmony_cibool JSHClass::UnregisterOnProtoChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
10124514f5e3Sopenharmony_ci{
10134514f5e3Sopenharmony_ci    ASSERT(jshclass->IsPrototype());
10144514f5e3Sopenharmony_ci    if (!jshclass->GetProtoChangeDetails().IsProtoChangeDetails()) {
10154514f5e3Sopenharmony_ci        return false;
10164514f5e3Sopenharmony_ci    }
10174514f5e3Sopenharmony_ci    if (!jshclass->GetPrototype().IsECMAObject()) {
10184514f5e3Sopenharmony_ci        JSTaggedValue listeners =
10194514f5e3Sopenharmony_ci            ProtoChangeDetails::Cast(jshclass->GetProtoChangeDetails().GetTaggedObject())->GetChangeListener();
10204514f5e3Sopenharmony_ci        return !listeners.IsUndefined();
10214514f5e3Sopenharmony_ci    }
10224514f5e3Sopenharmony_ci    JSHandle<ProtoChangeDetails> currentDetails = GetProtoChangeDetails(thread, jshclass);
10234514f5e3Sopenharmony_ci    uint32_t index = currentDetails->GetRegisterIndex();
10244514f5e3Sopenharmony_ci    if (index == static_cast<uint32_t>(ProtoChangeDetails::UNREGISTERED)) {
10254514f5e3Sopenharmony_ci        return false;
10264514f5e3Sopenharmony_ci    }
10274514f5e3Sopenharmony_ci    JSTaggedValue proto = jshclass->GetPrototype();
10284514f5e3Sopenharmony_ci    ASSERT(proto.IsECMAObject());
10294514f5e3Sopenharmony_ci    JSTaggedValue protoDetailsValue = JSObject::Cast(proto.GetTaggedObject())->GetJSHClass()->GetProtoChangeDetails();
10304514f5e3Sopenharmony_ci    if (protoDetailsValue.IsUndefined() || protoDetailsValue.IsNull()) {
10314514f5e3Sopenharmony_ci        return false;
10324514f5e3Sopenharmony_ci    }
10334514f5e3Sopenharmony_ci    ASSERT(protoDetailsValue.IsProtoChangeDetails());
10344514f5e3Sopenharmony_ci    JSTaggedValue listenersValue = ProtoChangeDetails::Cast(protoDetailsValue.GetTaggedObject())->GetChangeListener();
10354514f5e3Sopenharmony_ci    ASSERT(!listenersValue.IsUndefined());
10364514f5e3Sopenharmony_ci    JSHandle<ChangeListener> listeners(thread, listenersValue.GetTaggedObject());
10374514f5e3Sopenharmony_ci    ASSERT(listeners->Get(index) == jshclass.GetTaggedValue());
10384514f5e3Sopenharmony_ci    listeners->Delete(thread, index);
10394514f5e3Sopenharmony_ci    return true;
10404514f5e3Sopenharmony_ci}
10414514f5e3Sopenharmony_ci
10424514f5e3Sopenharmony_ciJSHandle<ProtoChangeDetails> JSHClass::GetProtoChangeDetails(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
10434514f5e3Sopenharmony_ci{
10444514f5e3Sopenharmony_ci    JSTaggedValue protoDetails = jshclass->GetProtoChangeDetails();
10454514f5e3Sopenharmony_ci    if (protoDetails.IsProtoChangeDetails()) {
10464514f5e3Sopenharmony_ci        return JSHandle<ProtoChangeDetails>(thread, protoDetails);
10474514f5e3Sopenharmony_ci    }
10484514f5e3Sopenharmony_ci    JSHandle<ProtoChangeDetails> protoDetailsHandle = thread->GetEcmaVM()->GetFactory()->NewProtoChangeDetails();
10494514f5e3Sopenharmony_ci    jshclass->SetProtoChangeDetails(thread, protoDetailsHandle.GetTaggedValue());
10504514f5e3Sopenharmony_ci    return protoDetailsHandle;
10514514f5e3Sopenharmony_ci}
10524514f5e3Sopenharmony_ci
10534514f5e3Sopenharmony_ciJSHandle<ProtoChangeDetails> JSHClass::GetProtoChangeDetails(const JSThread *thread, const JSHandle<JSObject> &obj)
10544514f5e3Sopenharmony_ci{
10554514f5e3Sopenharmony_ci    JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
10564514f5e3Sopenharmony_ci    return GetProtoChangeDetails(thread, jshclass);
10574514f5e3Sopenharmony_ci}
10584514f5e3Sopenharmony_ci
10594514f5e3Sopenharmony_civoid JSHClass::MarkProtoChanged([[maybe_unused]] const JSThread *thread, const JSHandle<JSHClass> &jshclass)
10604514f5e3Sopenharmony_ci{
10614514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
10624514f5e3Sopenharmony_ci    ASSERT(jshclass->IsPrototype());
10634514f5e3Sopenharmony_ci    JSTaggedValue markerValue = jshclass->GetProtoChangeMarker();
10644514f5e3Sopenharmony_ci    if (markerValue.IsProtoChangeMarker()) {
10654514f5e3Sopenharmony_ci        ProtoChangeMarker *protoChangeMarker = ProtoChangeMarker::Cast(markerValue.GetTaggedObject());
10664514f5e3Sopenharmony_ci        protoChangeMarker->SetHasChanged(true);
10674514f5e3Sopenharmony_ci    }
10684514f5e3Sopenharmony_ci}
10694514f5e3Sopenharmony_ci
10704514f5e3Sopenharmony_civoid JSHClass::NoticeThroughChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
10714514f5e3Sopenharmony_ci                                  JSTaggedValue addedKey)
10724514f5e3Sopenharmony_ci{
10734514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
10744514f5e3Sopenharmony_ci    MarkProtoChanged(thread, jshclass);
10754514f5e3Sopenharmony_ci    JSTaggedValue protoDetailsValue = jshclass->GetProtoChangeDetails();
10764514f5e3Sopenharmony_ci    if (!protoDetailsValue.IsProtoChangeDetails()) {
10774514f5e3Sopenharmony_ci        return;
10784514f5e3Sopenharmony_ci    }
10794514f5e3Sopenharmony_ci    JSTaggedValue listenersValue = ProtoChangeDetails::Cast(protoDetailsValue.GetTaggedObject())->GetChangeListener();
10804514f5e3Sopenharmony_ci    if (!listenersValue.IsTaggedArray()) {
10814514f5e3Sopenharmony_ci        return;
10824514f5e3Sopenharmony_ci    }
10834514f5e3Sopenharmony_ci    ChangeListener *listeners = ChangeListener::Cast(listenersValue.GetTaggedObject());
10844514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < listeners->GetEnd(); i++) {
10854514f5e3Sopenharmony_ci        JSTaggedValue temp = listeners->Get(i);
10864514f5e3Sopenharmony_ci        if (temp.IsJSHClass()) {
10874514f5e3Sopenharmony_ci            NoticeThroughChain(thread, JSHandle<JSHClass>(thread, listeners->Get(i).GetTaggedObject()), addedKey);
10884514f5e3Sopenharmony_ci        }
10894514f5e3Sopenharmony_ci    }
10904514f5e3Sopenharmony_ci}
10914514f5e3Sopenharmony_ci
10924514f5e3Sopenharmony_civoid JSHClass::RefreshUsers(const JSThread *thread, const JSHandle<JSHClass> &oldHclass,
10934514f5e3Sopenharmony_ci                            const JSHandle<JSHClass> &newHclass)
10944514f5e3Sopenharmony_ci{
10954514f5e3Sopenharmony_ci    ASSERT(oldHclass->IsPrototype());
10964514f5e3Sopenharmony_ci    ASSERT(newHclass->IsPrototype());
10974514f5e3Sopenharmony_ci    bool onceRegistered = UnregisterOnProtoChain(thread, oldHclass);
10984514f5e3Sopenharmony_ci
10994514f5e3Sopenharmony_ci    // oldHclass is already marked. Only update newHclass.protoChangeDetails if it doesn't exist for further use.
11004514f5e3Sopenharmony_ci    if (!newHclass->GetProtoChangeDetails().IsProtoChangeDetails()) {
11014514f5e3Sopenharmony_ci        newHclass->SetProtoChangeDetails(thread, oldHclass->GetProtoChangeDetails());
11024514f5e3Sopenharmony_ci    }
11034514f5e3Sopenharmony_ci    oldHclass->SetProtoChangeDetails(thread, JSTaggedValue::Undefined());
11044514f5e3Sopenharmony_ci    if (onceRegistered) {
11054514f5e3Sopenharmony_ci        if (newHclass->GetProtoChangeDetails().IsProtoChangeDetails()) {
11064514f5e3Sopenharmony_ci            ProtoChangeDetails::Cast(newHclass->GetProtoChangeDetails().GetTaggedObject())
11074514f5e3Sopenharmony_ci                ->SetRegisterIndex(ProtoChangeDetails::UNREGISTERED);
11084514f5e3Sopenharmony_ci        }
11094514f5e3Sopenharmony_ci        RegisterOnProtoChain(thread, newHclass);
11104514f5e3Sopenharmony_ci    }
11114514f5e3Sopenharmony_ci}
11124514f5e3Sopenharmony_ci
11134514f5e3Sopenharmony_ciPropertyLookupResult JSHClass::LookupPropertyInAotHClass(const JSThread *thread, JSHClass *hclass, JSTaggedValue key)
11144514f5e3Sopenharmony_ci{
11154514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
11164514f5e3Sopenharmony_ci    ASSERT(hclass->IsTS());
11174514f5e3Sopenharmony_ci
11184514f5e3Sopenharmony_ci    PropertyLookupResult result;
11194514f5e3Sopenharmony_ci    if (hclass->IsDictionaryMode()) {
11204514f5e3Sopenharmony_ci        // not fuond
11214514f5e3Sopenharmony_ci        result.SetIsFound(false);
11224514f5e3Sopenharmony_ci        return result;
11234514f5e3Sopenharmony_ci    }
11244514f5e3Sopenharmony_ci
11254514f5e3Sopenharmony_ci    int entry = JSHClass::FindPropertyEntry(thread, hclass, key);
11264514f5e3Sopenharmony_ci    // found in local
11274514f5e3Sopenharmony_ci    if (entry != -1) {
11284514f5e3Sopenharmony_ci        result.SetIsFound(true);
11294514f5e3Sopenharmony_ci        result.SetIsLocal(true);
11304514f5e3Sopenharmony_ci        PropertyAttributes attr = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject())->GetAttr(entry);
11314514f5e3Sopenharmony_ci        if (attr.IsInlinedProps()) {
11324514f5e3Sopenharmony_ci            result.SetIsInlinedProps(true);
11334514f5e3Sopenharmony_ci            result.SetOffset(hclass->GetInlinedPropertiesOffset(entry));
11344514f5e3Sopenharmony_ci        } else {
11354514f5e3Sopenharmony_ci            result.SetIsInlinedProps(false);
11364514f5e3Sopenharmony_ci            result.SetOffset(attr.GetOffset() - hclass->GetInlinedProperties());
11374514f5e3Sopenharmony_ci        }
11384514f5e3Sopenharmony_ci        if (attr.IsNotHole()) {
11394514f5e3Sopenharmony_ci            result.SetIsNotHole(true);
11404514f5e3Sopenharmony_ci        }
11414514f5e3Sopenharmony_ci        if (attr.IsAccessor()) {
11424514f5e3Sopenharmony_ci            result.SetIsAccessor(true);
11434514f5e3Sopenharmony_ci        }
11444514f5e3Sopenharmony_ci        result.SetRepresentation(attr.GetRepresentation());
11454514f5e3Sopenharmony_ci        result.SetIsWritable(attr.IsWritable());
11464514f5e3Sopenharmony_ci        return result;
11474514f5e3Sopenharmony_ci    }
11484514f5e3Sopenharmony_ci
11494514f5e3Sopenharmony_ci    // not found
11504514f5e3Sopenharmony_ci    result.SetIsFound(false);
11514514f5e3Sopenharmony_ci    return result;
11524514f5e3Sopenharmony_ci}
11534514f5e3Sopenharmony_ci
11544514f5e3Sopenharmony_ciPropertyLookupResult JSHClass::LookupPropertyInPGOHClass(const JSThread *thread, JSHClass *hclass, JSTaggedValue key)
11554514f5e3Sopenharmony_ci{
11564514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
11574514f5e3Sopenharmony_ci
11584514f5e3Sopenharmony_ci    PropertyLookupResult result;
11594514f5e3Sopenharmony_ci    if (hclass->IsDictionaryMode()) {
11604514f5e3Sopenharmony_ci        result.SetIsFound(false);
11614514f5e3Sopenharmony_ci        return result;
11624514f5e3Sopenharmony_ci    }
11634514f5e3Sopenharmony_ci
11644514f5e3Sopenharmony_ci    int entry = JSHClass::FindPropertyEntry(thread, hclass, key);
11654514f5e3Sopenharmony_ci    // found in local
11664514f5e3Sopenharmony_ci    if (entry != -1) {
11674514f5e3Sopenharmony_ci        result.SetIsFound(true);
11684514f5e3Sopenharmony_ci        result.SetIsLocal(true);
11694514f5e3Sopenharmony_ci        PropertyAttributes attr = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject())->GetAttr(entry);
11704514f5e3Sopenharmony_ci        if (attr.IsInlinedProps()) {
11714514f5e3Sopenharmony_ci            result.SetIsInlinedProps(true);
11724514f5e3Sopenharmony_ci            result.SetOffset(hclass->GetInlinedPropertiesOffset(entry));
11734514f5e3Sopenharmony_ci        } else {
11744514f5e3Sopenharmony_ci            result.SetIsInlinedProps(false);
11754514f5e3Sopenharmony_ci            result.SetOffset(attr.GetOffset() - hclass->GetInlinedProperties());
11764514f5e3Sopenharmony_ci        }
11774514f5e3Sopenharmony_ci
11784514f5e3Sopenharmony_ci        if (attr.IsNotHole()) {
11794514f5e3Sopenharmony_ci            result.SetIsNotHole(true);
11804514f5e3Sopenharmony_ci        }
11814514f5e3Sopenharmony_ci        if (attr.IsAccessor()) {
11824514f5e3Sopenharmony_ci            result.SetIsAccessor(true);
11834514f5e3Sopenharmony_ci        }
11844514f5e3Sopenharmony_ci        result.SetRepresentation(attr.GetRepresentation());
11854514f5e3Sopenharmony_ci        result.SetIsWritable(attr.IsWritable());
11864514f5e3Sopenharmony_ci        return result;
11874514f5e3Sopenharmony_ci    }
11884514f5e3Sopenharmony_ci
11894514f5e3Sopenharmony_ci    // not fuond
11904514f5e3Sopenharmony_ci    result.SetIsFound(false);
11914514f5e3Sopenharmony_ci    return result;
11924514f5e3Sopenharmony_ci}
11934514f5e3Sopenharmony_ci
11944514f5e3Sopenharmony_ciPropertyLookupResult JSHClass::LookupPropertyInBuiltinPrototypeHClass(const JSThread *thread, JSHClass *hclass,
11954514f5e3Sopenharmony_ci                                                                      JSTaggedValue key)
11964514f5e3Sopenharmony_ci{
11974514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
11984514f5e3Sopenharmony_ci    ASSERT(hclass->IsPrototype());
11994514f5e3Sopenharmony_ci
12004514f5e3Sopenharmony_ci    PropertyLookupResult result;
12014514f5e3Sopenharmony_ci    if (hclass->IsDictionaryMode()) {
12024514f5e3Sopenharmony_ci        // not fuond
12034514f5e3Sopenharmony_ci        result.SetIsFound(false);
12044514f5e3Sopenharmony_ci        return result;
12054514f5e3Sopenharmony_ci    }
12064514f5e3Sopenharmony_ci    int entry = JSHClass::FindPropertyEntry(thread, hclass, key);
12074514f5e3Sopenharmony_ci    // When the property is not found, the value of 'entry' is -1.
12084514f5e3Sopenharmony_ci    // Currently, not all methods on the prototype of 'builtin' have been changed to inlined.
12094514f5e3Sopenharmony_ci    // Therefore, when a non-inlined method is encountered, it is also considered not found.
12104514f5e3Sopenharmony_ci    if (entry == -1 || static_cast<uint32_t>(entry) >= hclass->GetInlinedProperties()) {
12114514f5e3Sopenharmony_ci        result.SetIsFound(false);
12124514f5e3Sopenharmony_ci        return result;
12134514f5e3Sopenharmony_ci    }
12144514f5e3Sopenharmony_ci
12154514f5e3Sopenharmony_ci    result.SetIsFound(true);
12164514f5e3Sopenharmony_ci    result.SetIsLocal(true);
12174514f5e3Sopenharmony_ci    PropertyAttributes attr = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject())->GetAttr(entry);
12184514f5e3Sopenharmony_ci    if (attr.IsInlinedProps()) {
12194514f5e3Sopenharmony_ci        result.SetIsInlinedProps(true);
12204514f5e3Sopenharmony_ci        result.SetOffset(hclass->GetInlinedPropertiesOffset(entry));
12214514f5e3Sopenharmony_ci    } else {
12224514f5e3Sopenharmony_ci        result.SetIsInlinedProps(false);
12234514f5e3Sopenharmony_ci        result.SetOffset(attr.GetOffset() - hclass->GetInlinedProperties());
12244514f5e3Sopenharmony_ci    }
12254514f5e3Sopenharmony_ci    result.SetIsNotHole(true);
12264514f5e3Sopenharmony_ci    if (attr.IsAccessor()) {
12274514f5e3Sopenharmony_ci        result.SetIsAccessor(true);
12284514f5e3Sopenharmony_ci    }
12294514f5e3Sopenharmony_ci    result.SetRepresentation(attr.GetRepresentation());
12304514f5e3Sopenharmony_ci    result.SetIsWritable(attr.IsWritable());
12314514f5e3Sopenharmony_ci    return result;
12324514f5e3Sopenharmony_ci}
12334514f5e3Sopenharmony_ci
12344514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSHClass::ParseKeyFromPGOCString(ObjectFactory* factory,
12354514f5e3Sopenharmony_ci                                                         const CString& cstring,
12364514f5e3Sopenharmony_ci                                                         const PGOHandler& handler)
12374514f5e3Sopenharmony_ci{
12384514f5e3Sopenharmony_ci    if (handler.GetIsSymbol()) {
12394514f5e3Sopenharmony_ci        JSHandle<JSSymbol> symbol;
12404514f5e3Sopenharmony_ci        auto str = cstring.substr(0, 6); // `method` length is 6
12414514f5e3Sopenharmony_ci        if (str == "method") { // cstring is `method_0ULL` after _ is private id of symbol
12424514f5e3Sopenharmony_ci            symbol = factory->NewPublicSymbolWithChar("method");
12434514f5e3Sopenharmony_ci            ASSERT(cstring.size() > 0);
12444514f5e3Sopenharmony_ci            str = cstring.substr(7, cstring.size() - 1); // `method_` length is 7
12454514f5e3Sopenharmony_ci            symbol->SetPrivateId(CStringToULL(str));
12464514f5e3Sopenharmony_ci        } else { // cstring is private id of symbol
12474514f5e3Sopenharmony_ci            symbol = factory->NewJSSymbol();
12484514f5e3Sopenharmony_ci            symbol->SetPrivateId(CStringToULL(cstring));
12494514f5e3Sopenharmony_ci        }
12504514f5e3Sopenharmony_ci        return JSHandle<JSTaggedValue>(symbol);
12514514f5e3Sopenharmony_ci    } else {
12524514f5e3Sopenharmony_ci        return JSHandle<JSTaggedValue>(factory->NewFromStdString(std::string(cstring)));
12534514f5e3Sopenharmony_ci    }
12544514f5e3Sopenharmony_ci}
12554514f5e3Sopenharmony_ci
12564514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::CreateRootHClassFromPGO(const JSThread* thread,
12574514f5e3Sopenharmony_ci                                                     const HClassLayoutDesc* desc,
12584514f5e3Sopenharmony_ci                                                     uint32_t maxNum,
12594514f5e3Sopenharmony_ci                                                     bool isCache)
12604514f5e3Sopenharmony_ci{
12614514f5e3Sopenharmony_ci    if (isCache) {
12624514f5e3Sopenharmony_ci        if (ObjectFactory::CanObjectLiteralHClassCache(maxNum)) {
12634514f5e3Sopenharmony_ci            return CreateRootHClassWithCached(thread, desc, maxNum);
12644514f5e3Sopenharmony_ci        }
12654514f5e3Sopenharmony_ci    }
12664514f5e3Sopenharmony_ci    auto rootDesc = reinterpret_cast<const pgo::RootHClassLayoutDesc *>(desc);
12674514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
12684514f5e3Sopenharmony_ci    uint32_t numOfProps = rootDesc->NumOfProps();
12694514f5e3Sopenharmony_ci    uint32_t index = 0;
12704514f5e3Sopenharmony_ci    JSType type = rootDesc->GetObjectType();
12714514f5e3Sopenharmony_ci    size_t size = rootDesc->GetObjectSize();
12724514f5e3Sopenharmony_ci    JSHandle<JSHClass> hclass = factory->NewEcmaHClass(size, type, maxNum);
12734514f5e3Sopenharmony_ci    // Dictionary?
12744514f5e3Sopenharmony_ci    JSHandle<LayoutInfo> layout = factory->CreateLayoutInfo(maxNum, MemSpaceType::SEMI_SPACE, GrowMode::KEEP);
12754514f5e3Sopenharmony_ci    rootDesc->IterateProps([thread, factory, &index, hclass, layout](const pgo::PropertyDesc& propDesc) {
12764514f5e3Sopenharmony_ci        auto& cstring = propDesc.first;
12774514f5e3Sopenharmony_ci        auto& handler = propDesc.second;
12784514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> key = ParseKeyFromPGOCString(factory, cstring, handler);
12794514f5e3Sopenharmony_ci        PropertyAttributes attributes = PropertyAttributes::Default();
12804514f5e3Sopenharmony_ci        if (handler.SetAttribute(thread, attributes)) {
12814514f5e3Sopenharmony_ci            hclass->SetIsAllTaggedProp(false);
12824514f5e3Sopenharmony_ci        }
12834514f5e3Sopenharmony_ci        attributes.SetIsInlinedProps(true);
12844514f5e3Sopenharmony_ci        attributes.SetOffset(index);
12854514f5e3Sopenharmony_ci        layout->AddKey(thread, index, key.GetTaggedValue(), attributes);
12864514f5e3Sopenharmony_ci        index++;
12874514f5e3Sopenharmony_ci    });
12884514f5e3Sopenharmony_ci    hclass->SetLayout(thread, layout);
12894514f5e3Sopenharmony_ci    hclass->SetNumberOfProps(numOfProps);
12904514f5e3Sopenharmony_ci    hclass->SetTS(true);
12914514f5e3Sopenharmony_ci    return hclass;
12924514f5e3Sopenharmony_ci}
12934514f5e3Sopenharmony_ci
12944514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::CreateRootHClassWithCached(const JSThread* thread,
12954514f5e3Sopenharmony_ci                                                        const HClassLayoutDesc* desc,
12964514f5e3Sopenharmony_ci                                                        uint32_t maxNum)
12974514f5e3Sopenharmony_ci{
12984514f5e3Sopenharmony_ci    auto rootDesc = reinterpret_cast<const pgo::RootHClassLayoutDesc *>(desc);
12994514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
13004514f5e3Sopenharmony_ci    uint32_t index = 0;
13014514f5e3Sopenharmony_ci    ASSERT(rootDesc->GetObjectSize() == JSObject::SIZE);
13024514f5e3Sopenharmony_ci    ASSERT(rootDesc->GetObjectType() == JSType::JS_OBJECT);
13034514f5e3Sopenharmony_ci    JSHandle<JSHClass> hclass = factory->GetObjectLiteralRootHClass(maxNum);
13044514f5e3Sopenharmony_ci    JSHandle<LayoutInfo> layout = factory->CreateLayoutInfo(maxNum, MemSpaceType::SEMI_SPACE, GrowMode::KEEP);
13054514f5e3Sopenharmony_ci    hclass->SetPrototype(thread, JSTaggedValue::Null());
13064514f5e3Sopenharmony_ci    hclass->SetLayout(thread, layout);
13074514f5e3Sopenharmony_ci    hclass->SetTS(true);
13084514f5e3Sopenharmony_ci    rootDesc->IterateProps([thread, factory, &index, &hclass](const pgo::PropertyDesc& propDesc) {
13094514f5e3Sopenharmony_ci        auto& cstring = propDesc.first;
13104514f5e3Sopenharmony_ci        auto& handler = propDesc.second;
13114514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> key = ParseKeyFromPGOCString(factory, cstring, handler);
13124514f5e3Sopenharmony_ci        PropertyAttributes attributes = PropertyAttributes::Default();
13134514f5e3Sopenharmony_ci        if (handler.SetAttribute(thread, attributes)) {
13144514f5e3Sopenharmony_ci            hclass->SetIsAllTaggedProp(false);
13154514f5e3Sopenharmony_ci        }
13164514f5e3Sopenharmony_ci        attributes.SetIsInlinedProps(true);
13174514f5e3Sopenharmony_ci        attributes.SetOffset(index++);
13184514f5e3Sopenharmony_ci        auto rep = attributes.GetRepresentation();
13194514f5e3Sopenharmony_ci
13204514f5e3Sopenharmony_ci        JSHandle<JSHClass> child = SetPropertyOfObjHClass(thread, hclass, key, attributes, rep);
13214514f5e3Sopenharmony_ci        child->SetParent(thread, hclass);
13224514f5e3Sopenharmony_ci        child->SetPrototype(thread, JSTaggedValue::Null());
13234514f5e3Sopenharmony_ci        child->SetTS(true);
13244514f5e3Sopenharmony_ci        hclass = child;
13254514f5e3Sopenharmony_ci    });
13264514f5e3Sopenharmony_ci    return hclass;
13274514f5e3Sopenharmony_ci}
13284514f5e3Sopenharmony_ci
13294514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::CreateChildHClassFromPGO(const JSThread* thread,
13304514f5e3Sopenharmony_ci                                                      const JSHandle<JSHClass>& parent,
13314514f5e3Sopenharmony_ci                                                      const HClassLayoutDesc* desc)
13324514f5e3Sopenharmony_ci{
13334514f5e3Sopenharmony_ci    pgo::PropertyDesc propDesc = reinterpret_cast<const pgo::ChildHClassLayoutDesc *>(desc)->GetPropertyDesc();
13344514f5e3Sopenharmony_ci    auto& cstring = propDesc.first;
13354514f5e3Sopenharmony_ci    auto& handler = propDesc.second;
13364514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
13374514f5e3Sopenharmony_ci    uint32_t numOfProps = parent->NumberOfProps();
13384514f5e3Sopenharmony_ci
13394514f5e3Sopenharmony_ci    JSHandle<JSHClass> newJsHClass = JSHClass::Clone(thread, parent);
13404514f5e3Sopenharmony_ci    newJsHClass->SetTS(true);
13414514f5e3Sopenharmony_ci    ASSERT(newJsHClass->GetInlinedProperties() >= (numOfProps + 1));
13424514f5e3Sopenharmony_ci    uint32_t offset = numOfProps;
13434514f5e3Sopenharmony_ci    {
13444514f5e3Sopenharmony_ci        JSMutableHandle<LayoutInfo> layoutInfoHandle(thread, newJsHClass->GetLayout());
13454514f5e3Sopenharmony_ci        if (layoutInfoHandle->NumberOfElements() != static_cast<int>(offset)) {
13464514f5e3Sopenharmony_ci            layoutInfoHandle.Update(factory->CopyAndReSort(layoutInfoHandle, offset, offset + 1));
13474514f5e3Sopenharmony_ci            newJsHClass->SetLayout(thread, layoutInfoHandle);
13484514f5e3Sopenharmony_ci        } else if (layoutInfoHandle->GetPropertiesCapacity() <= static_cast<int>(offset)) {  // need to Grow
13494514f5e3Sopenharmony_ci            layoutInfoHandle.Update(
13504514f5e3Sopenharmony_ci                factory->ExtendLayoutInfo(layoutInfoHandle, offset));
13514514f5e3Sopenharmony_ci            newJsHClass->SetLayout(thread, layoutInfoHandle);
13524514f5e3Sopenharmony_ci        }
13534514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> key = ParseKeyFromPGOCString(factory, cstring, handler);
13544514f5e3Sopenharmony_ci        PropertyAttributes attributes = PropertyAttributes::Default();
13554514f5e3Sopenharmony_ci        if (handler.SetAttribute(thread, attributes)) {
13564514f5e3Sopenharmony_ci            newJsHClass->SetIsAllTaggedProp(false);
13574514f5e3Sopenharmony_ci        }
13584514f5e3Sopenharmony_ci        attributes.SetOffset(offset);
13594514f5e3Sopenharmony_ci        attributes.SetIsInlinedProps(true);
13604514f5e3Sopenharmony_ci        layoutInfoHandle->AddKey(thread, offset, key.GetTaggedValue(), attributes);
13614514f5e3Sopenharmony_ci        newJsHClass->IncNumberOfProps();
13624514f5e3Sopenharmony_ci        AddTransitions(thread, parent, newJsHClass, key, attributes);
13634514f5e3Sopenharmony_ci        JSHClass::NotifyHclassChanged(thread, parent, newJsHClass, key.GetTaggedValue());
13644514f5e3Sopenharmony_ci    }
13654514f5e3Sopenharmony_ci
13664514f5e3Sopenharmony_ci    return newJsHClass;
13674514f5e3Sopenharmony_ci}
13684514f5e3Sopenharmony_ci
13694514f5e3Sopenharmony_cibool JSHClass::DumpRootHClassByPGO(const JSHClass* hclass, HClassLayoutDesc* desc)
13704514f5e3Sopenharmony_ci{
13714514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
13724514f5e3Sopenharmony_ci    if (hclass->IsDictionaryMode()) {
13734514f5e3Sopenharmony_ci        return false;
13744514f5e3Sopenharmony_ci    }
13754514f5e3Sopenharmony_ci
13764514f5e3Sopenharmony_ci    LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
13774514f5e3Sopenharmony_ci    int element = static_cast<int>(hclass->NumberOfProps());
13784514f5e3Sopenharmony_ci    for (int i = 0; i < element; i++) {
13794514f5e3Sopenharmony_ci        layout->DumpFieldIndexByPGO(i, desc);
13804514f5e3Sopenharmony_ci    }
13814514f5e3Sopenharmony_ci    return true;
13824514f5e3Sopenharmony_ci}
13834514f5e3Sopenharmony_ci
13844514f5e3Sopenharmony_cibool JSHClass::DumpChildHClassByPGO(const JSHClass* hclass, HClassLayoutDesc* desc)
13854514f5e3Sopenharmony_ci{
13864514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
13874514f5e3Sopenharmony_ci    if (hclass->IsDictionaryMode()) {
13884514f5e3Sopenharmony_ci        return false;
13894514f5e3Sopenharmony_ci    }
13904514f5e3Sopenharmony_ci    if (hclass->PropsIsEmpty()) {
13914514f5e3Sopenharmony_ci        return false;
13924514f5e3Sopenharmony_ci    }
13934514f5e3Sopenharmony_ci    uint32_t last = hclass->LastPropIndex();
13944514f5e3Sopenharmony_ci    LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
13954514f5e3Sopenharmony_ci    layoutInfo->DumpFieldIndexByPGO(last, desc);
13964514f5e3Sopenharmony_ci    return true;
13974514f5e3Sopenharmony_ci}
13984514f5e3Sopenharmony_ci
13994514f5e3Sopenharmony_cibool JSHClass::UpdateChildLayoutDescByPGO(const JSHClass* hclass, HClassLayoutDesc* childDesc)
14004514f5e3Sopenharmony_ci{
14014514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
14024514f5e3Sopenharmony_ci    if (hclass->IsDictionaryMode()) {
14034514f5e3Sopenharmony_ci        return false;
14044514f5e3Sopenharmony_ci    }
14054514f5e3Sopenharmony_ci    if (hclass->PropsIsEmpty()) {
14064514f5e3Sopenharmony_ci        return false;
14074514f5e3Sopenharmony_ci    }
14084514f5e3Sopenharmony_ci    uint32_t last = hclass->LastPropIndex();
14094514f5e3Sopenharmony_ci    LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
14104514f5e3Sopenharmony_ci    return layoutInfo->UpdateFieldIndexByPGO(last, childDesc);
14114514f5e3Sopenharmony_ci}
14124514f5e3Sopenharmony_ci
14134514f5e3Sopenharmony_cibool JSHClass::UpdateRootLayoutDescByPGO(const JSHClass* hclass, HClassLayoutDesc* desc)
14144514f5e3Sopenharmony_ci{
14154514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
14164514f5e3Sopenharmony_ci    if (hclass->IsDictionaryMode()) {
14174514f5e3Sopenharmony_ci        return false;
14184514f5e3Sopenharmony_ci    }
14194514f5e3Sopenharmony_ci
14204514f5e3Sopenharmony_ci    auto rootDesc = reinterpret_cast<const pgo::RootHClassLayoutDesc *>(desc);
14214514f5e3Sopenharmony_ci    int rootPropLen = static_cast<int>(rootDesc->NumOfProps());
14224514f5e3Sopenharmony_ci    LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
14234514f5e3Sopenharmony_ci    for (int i = 0; i < rootPropLen; i++) {
14244514f5e3Sopenharmony_ci        layout->UpdateFieldIndexByPGO(i, desc);
14254514f5e3Sopenharmony_ci    }
14264514f5e3Sopenharmony_ci    return true;
14274514f5e3Sopenharmony_ci}
14284514f5e3Sopenharmony_ci
14294514f5e3Sopenharmony_ciCString JSHClass::DumpToString(JSTaggedType hclassVal)
14304514f5e3Sopenharmony_ci{
14314514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
14324514f5e3Sopenharmony_ci    auto hclass = JSHClass::Cast(JSTaggedValue(hclassVal).GetTaggedObject());
14334514f5e3Sopenharmony_ci    if (hclass->IsDictionaryMode()) {
14344514f5e3Sopenharmony_ci        return "";
14354514f5e3Sopenharmony_ci    }
14364514f5e3Sopenharmony_ci
14374514f5e3Sopenharmony_ci    CString result;
14384514f5e3Sopenharmony_ci    LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
14394514f5e3Sopenharmony_ci    int element = static_cast<int>(hclass->NumberOfProps());
14404514f5e3Sopenharmony_ci    for (int i = 0; i < element; i++) {
14414514f5e3Sopenharmony_ci        auto key = layout->GetKey(i);
14424514f5e3Sopenharmony_ci        if (key.IsString()) {
14434514f5e3Sopenharmony_ci            uint64_t value = EcmaStringAccessor(key).GetHashcode();
14444514f5e3Sopenharmony_ci            value <<= sizeof(uint32_t) * BITS_PER_BYTE;
14454514f5e3Sopenharmony_ci            auto attr = layout->GetAttr(i);
14464514f5e3Sopenharmony_ci            auto defaultAttr = PropertyAttributes(attr.GetPropertyMetaData());
14474514f5e3Sopenharmony_ci            defaultAttr.SetTrackType(attr.GetTrackType());
14484514f5e3Sopenharmony_ci            value += defaultAttr.GetValue();
14494514f5e3Sopenharmony_ci            result += ToCString(value);
14504514f5e3Sopenharmony_ci        } else if (key.IsSymbol()) {
14514514f5e3Sopenharmony_ci            result += JSSymbol::Cast(key)->GetPrivateId();
14524514f5e3Sopenharmony_ci            auto attr = layout->GetAttr(i);
14534514f5e3Sopenharmony_ci            result += static_cast<int32_t>(attr.GetTrackType());
14544514f5e3Sopenharmony_ci            result += attr.GetPropertyMetaData();
14554514f5e3Sopenharmony_ci        } else {
14564514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "JSHClass::DumpToString UNREACHABLE";
14574514f5e3Sopenharmony_ci        }
14584514f5e3Sopenharmony_ci    }
14594514f5e3Sopenharmony_ci    return result;
14604514f5e3Sopenharmony_ci}
14614514f5e3Sopenharmony_ci
14624514f5e3Sopenharmony_ciPropertyLookupResult JSHClass::LookupPropertyInBuiltinHClass(const JSThread *thread, JSHClass *hclass,
14634514f5e3Sopenharmony_ci                                                             JSTaggedValue key)
14644514f5e3Sopenharmony_ci{
14654514f5e3Sopenharmony_ci    DISALLOW_GARBAGE_COLLECTION;
14664514f5e3Sopenharmony_ci
14674514f5e3Sopenharmony_ci    PropertyLookupResult result;
14684514f5e3Sopenharmony_ci    if (hclass->IsDictionaryMode()) {
14694514f5e3Sopenharmony_ci        result.SetIsFound(false);
14704514f5e3Sopenharmony_ci        return result;
14714514f5e3Sopenharmony_ci    }
14724514f5e3Sopenharmony_ci
14734514f5e3Sopenharmony_ci    int entry = JSHClass::FindPropertyEntry(thread, hclass, key);
14744514f5e3Sopenharmony_ci    // found in local
14754514f5e3Sopenharmony_ci    if (entry != -1) {
14764514f5e3Sopenharmony_ci        result.SetIsFound(true);
14774514f5e3Sopenharmony_ci        result.SetIsLocal(true);
14784514f5e3Sopenharmony_ci        PropertyAttributes attr = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject())->GetAttr(entry);
14794514f5e3Sopenharmony_ci        if (attr.IsInlinedProps()) {
14804514f5e3Sopenharmony_ci            result.SetIsInlinedProps(true);
14814514f5e3Sopenharmony_ci            result.SetOffset(hclass->GetInlinedPropertiesOffset(entry));
14824514f5e3Sopenharmony_ci        } else {
14834514f5e3Sopenharmony_ci            result.SetIsInlinedProps(false);
14844514f5e3Sopenharmony_ci            result.SetOffset(attr.GetOffset() - hclass->GetInlinedProperties());
14854514f5e3Sopenharmony_ci        }
14864514f5e3Sopenharmony_ci
14874514f5e3Sopenharmony_ci        if (attr.IsNotHole()) {
14884514f5e3Sopenharmony_ci            result.SetIsNotHole(true);
14894514f5e3Sopenharmony_ci        }
14904514f5e3Sopenharmony_ci        if (attr.IsAccessor()) {
14914514f5e3Sopenharmony_ci            result.SetIsAccessor(true);
14924514f5e3Sopenharmony_ci        }
14934514f5e3Sopenharmony_ci        result.SetRepresentation(attr.GetRepresentation());
14944514f5e3Sopenharmony_ci        result.SetIsWritable(attr.IsWritable());
14954514f5e3Sopenharmony_ci        return result;
14964514f5e3Sopenharmony_ci    }
14974514f5e3Sopenharmony_ci
14984514f5e3Sopenharmony_ci    // not fuond
14994514f5e3Sopenharmony_ci    result.SetIsFound(false);
15004514f5e3Sopenharmony_ci    return result;
15014514f5e3Sopenharmony_ci}
15024514f5e3Sopenharmony_ci
15034514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::CreateSHClass(JSThread *thread,
15044514f5e3Sopenharmony_ci                                           const std::vector<PropertyDescriptor> &descs,
15054514f5e3Sopenharmony_ci                                           const JSHClass *parentHClass,
15064514f5e3Sopenharmony_ci                                           bool isFunction)
15074514f5e3Sopenharmony_ci{
15084514f5e3Sopenharmony_ci    EcmaVM *vm = thread->GetEcmaVM();
15094514f5e3Sopenharmony_ci    ObjectFactory *factory = vm->GetFactory();
15104514f5e3Sopenharmony_ci
15114514f5e3Sopenharmony_ci    uint32_t length = descs.size();
15124514f5e3Sopenharmony_ci    uint32_t maxInline = isFunction ? JSSharedFunction::MAX_INLINE : JSSharedObject::MAX_INLINE;
15134514f5e3Sopenharmony_ci
15144514f5e3Sopenharmony_ci    if (parentHClass) {
15154514f5e3Sopenharmony_ci        if (parentHClass->IsDictionaryMode()) {
15164514f5e3Sopenharmony_ci            auto dict = reinterpret_cast<NameDictionary *>(parentHClass->GetLayout().GetTaggedObject());
15174514f5e3Sopenharmony_ci            length += static_cast<uint32_t>(dict->EntriesCount());
15184514f5e3Sopenharmony_ci        } else {
15194514f5e3Sopenharmony_ci            length += parentHClass->NumberOfProps();
15204514f5e3Sopenharmony_ci        }
15214514f5e3Sopenharmony_ci    }
15224514f5e3Sopenharmony_ci
15234514f5e3Sopenharmony_ci    JSHandle<JSHClass> hclass =
15244514f5e3Sopenharmony_ci        isFunction ? factory->NewSEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, length)
15254514f5e3Sopenharmony_ci                   : factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, length);
15264514f5e3Sopenharmony_ci    if (LIKELY(length <= maxInline)) {
15274514f5e3Sopenharmony_ci        CreateSInlinedLayout(thread, descs, hclass, parentHClass);
15284514f5e3Sopenharmony_ci    } else {
15294514f5e3Sopenharmony_ci        CreateSDictLayout(thread, descs, hclass, parentHClass);
15304514f5e3Sopenharmony_ci    }
15314514f5e3Sopenharmony_ci
15324514f5e3Sopenharmony_ci    return hclass;
15334514f5e3Sopenharmony_ci}
15344514f5e3Sopenharmony_ci
15354514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::CreateSConstructorHClass(JSThread *thread, const std::vector<PropertyDescriptor> &descs)
15364514f5e3Sopenharmony_ci{
15374514f5e3Sopenharmony_ci    auto hclass = CreateSHClass(thread, descs, nullptr, true);
15384514f5e3Sopenharmony_ci    hclass->SetClassConstructor(true);
15394514f5e3Sopenharmony_ci    hclass->SetConstructor(true);
15404514f5e3Sopenharmony_ci    return hclass;
15414514f5e3Sopenharmony_ci}
15424514f5e3Sopenharmony_ci
15434514f5e3Sopenharmony_ciJSHandle<JSHClass> JSHClass::CreateSPrototypeHClass(JSThread *thread, const std::vector<PropertyDescriptor> &descs)
15444514f5e3Sopenharmony_ci{
15454514f5e3Sopenharmony_ci    auto hclass = CreateSHClass(thread, descs);
15464514f5e3Sopenharmony_ci    hclass->SetClassPrototype(true);
15474514f5e3Sopenharmony_ci    hclass->SetIsPrototype(true);
15484514f5e3Sopenharmony_ci    return hclass;
15494514f5e3Sopenharmony_ci}
15504514f5e3Sopenharmony_ci
15514514f5e3Sopenharmony_civoid JSHClass::CreateSInlinedLayout(JSThread *thread,
15524514f5e3Sopenharmony_ci                                    const std::vector<PropertyDescriptor> &descs,
15534514f5e3Sopenharmony_ci                                    const JSHandle<JSHClass> &hclass,
15544514f5e3Sopenharmony_ci                                    const JSHClass *parentHClass)
15554514f5e3Sopenharmony_ci{
15564514f5e3Sopenharmony_ci    EcmaVM *vm = thread->GetEcmaVM();
15574514f5e3Sopenharmony_ci    ObjectFactory *factory = vm->GetFactory();
15584514f5e3Sopenharmony_ci
15594514f5e3Sopenharmony_ci    uint32_t parentLength{0};
15604514f5e3Sopenharmony_ci    if (parentHClass) {
15614514f5e3Sopenharmony_ci        parentLength = parentHClass->NumberOfProps();
15624514f5e3Sopenharmony_ci    }
15634514f5e3Sopenharmony_ci    auto length = descs.size();
15644514f5e3Sopenharmony_ci    auto layout = factory->CreateSLayoutInfo(length + parentLength);
15654514f5e3Sopenharmony_ci
15664514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
15674514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < length; ++i) {
15684514f5e3Sopenharmony_ci        key.Update(descs[i].GetKey());
15694514f5e3Sopenharmony_ci        PropertyAttributes attr =
15704514f5e3Sopenharmony_ci            PropertyAttributes::Default(descs[i].IsWritable(), descs[i].IsEnumerable(), descs[i].IsConfigurable());
15714514f5e3Sopenharmony_ci        if (UNLIKELY(descs[i].GetValue()->IsAccessor())) {
15724514f5e3Sopenharmony_ci            attr.SetIsAccessor(true);
15734514f5e3Sopenharmony_ci        }
15744514f5e3Sopenharmony_ci        attr.SetIsInlinedProps(true);
15754514f5e3Sopenharmony_ci        attr.SetRepresentation(Representation::TAGGED);
15764514f5e3Sopenharmony_ci        attr.SetSharedFieldType(descs[i].GetSharedFieldType());
15774514f5e3Sopenharmony_ci        attr.SetOffset(i);
15784514f5e3Sopenharmony_ci        layout->AddKey(thread, i, key.GetTaggedValue(), attr);
15794514f5e3Sopenharmony_ci    }
15804514f5e3Sopenharmony_ci
15814514f5e3Sopenharmony_ci    auto index = length;
15824514f5e3Sopenharmony_ci    if (parentHClass) {
15834514f5e3Sopenharmony_ci        JSHandle<LayoutInfo> old(thread, parentHClass->GetLayout());
15844514f5e3Sopenharmony_ci        for (uint32_t i = 0; i < parentLength; i++) {
15854514f5e3Sopenharmony_ci            key.Update(old->GetKey(i));
15864514f5e3Sopenharmony_ci            auto entry = layout->FindElementWithCache(thread, *hclass, key.GetTaggedValue(), index);
15874514f5e3Sopenharmony_ci            if (entry != -1) {
15884514f5e3Sopenharmony_ci                continue;
15894514f5e3Sopenharmony_ci            }
15904514f5e3Sopenharmony_ci            auto attr = PropertyAttributes(old->GetAttr(i));
15914514f5e3Sopenharmony_ci            attr.SetOffset(index);
15924514f5e3Sopenharmony_ci            layout->AddKey(thread, index, old->GetKey(i), attr);
15934514f5e3Sopenharmony_ci            ++index;
15944514f5e3Sopenharmony_ci        }
15954514f5e3Sopenharmony_ci    }
15964514f5e3Sopenharmony_ci
15974514f5e3Sopenharmony_ci    hclass->SetLayout(thread, layout);
15984514f5e3Sopenharmony_ci    hclass->SetNumberOfProps(index);
15994514f5e3Sopenharmony_ci    auto inlinedPropsLength = hclass->GetInlinedProperties();
16004514f5e3Sopenharmony_ci    if (inlinedPropsLength > index) {
16014514f5e3Sopenharmony_ci        uint32_t duplicatedSize = (inlinedPropsLength - index) * JSTaggedValue::TaggedTypeSize();
16024514f5e3Sopenharmony_ci        hclass->SetObjectSize(hclass->GetObjectSize() - duplicatedSize);
16034514f5e3Sopenharmony_ci    }
16044514f5e3Sopenharmony_ci}
16054514f5e3Sopenharmony_ci
16064514f5e3Sopenharmony_civoid JSHClass::CreateSDictLayout(JSThread *thread,
16074514f5e3Sopenharmony_ci                                 const std::vector<PropertyDescriptor> &descs,
16084514f5e3Sopenharmony_ci                                 const JSHandle<JSHClass> &hclass,
16094514f5e3Sopenharmony_ci                                 const JSHClass *parentHClass)
16104514f5e3Sopenharmony_ci{
16114514f5e3Sopenharmony_ci    uint32_t parentLength{0};
16124514f5e3Sopenharmony_ci    if (parentHClass) {
16134514f5e3Sopenharmony_ci        if (parentHClass->IsDictionaryMode()) {
16144514f5e3Sopenharmony_ci            parentLength = static_cast<uint32_t>(
16154514f5e3Sopenharmony_ci                reinterpret_cast<NameDictionary *>(parentHClass->GetLayout().GetTaggedObject())->EntriesCount());
16164514f5e3Sopenharmony_ci        } else {
16174514f5e3Sopenharmony_ci            parentLength = parentHClass->NumberOfProps();
16184514f5e3Sopenharmony_ci        }
16194514f5e3Sopenharmony_ci    }
16204514f5e3Sopenharmony_ci    auto length = descs.size();
16214514f5e3Sopenharmony_ci    JSMutableHandle<NameDictionary> dict(
16224514f5e3Sopenharmony_ci        thread,
16234514f5e3Sopenharmony_ci        NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(length + parentLength)));
16244514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
16254514f5e3Sopenharmony_ci    auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
16264514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> value = globalConst->GetHandledUndefined();
16274514f5e3Sopenharmony_ci
16284514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < length; ++i) {
16294514f5e3Sopenharmony_ci        key.Update(descs[i].GetKey());
16304514f5e3Sopenharmony_ci        PropertyAttributes attr =
16314514f5e3Sopenharmony_ci            PropertyAttributes::Default(descs[i].IsWritable(), descs[i].IsEnumerable(), descs[i].IsConfigurable());
16324514f5e3Sopenharmony_ci        attr.SetSharedFieldType(descs[i].GetSharedFieldType());
16334514f5e3Sopenharmony_ci        attr.SetBoxType(PropertyBoxType::UNDEFINED);
16344514f5e3Sopenharmony_ci        JSHandle<NameDictionary> newDict = NameDictionary::Put(thread, dict, key, value, attr);
16354514f5e3Sopenharmony_ci        dict.Update(newDict);
16364514f5e3Sopenharmony_ci    }
16374514f5e3Sopenharmony_ci
16384514f5e3Sopenharmony_ci    if (parentHClass) {
16394514f5e3Sopenharmony_ci        if (parentHClass->IsDictionaryMode()) {
16404514f5e3Sopenharmony_ci            JSHandle<NameDictionary> old(thread, parentHClass->GetLayout());
16414514f5e3Sopenharmony_ci            std::vector<int> indexOrder = old->GetEnumerationOrder();
16424514f5e3Sopenharmony_ci            for (uint32_t i = 0; i < parentLength; i++) {
16434514f5e3Sopenharmony_ci                key.Update(old->GetKey(indexOrder[i]));
16444514f5e3Sopenharmony_ci                JSHandle<NameDictionary> newDict = NameDictionary::Put(
16454514f5e3Sopenharmony_ci                    thread, dict, key, value, PropertyAttributes(old->GetAttributes(indexOrder[i])));
16464514f5e3Sopenharmony_ci                dict.Update(newDict);
16474514f5e3Sopenharmony_ci            }
16484514f5e3Sopenharmony_ci        } else {
16494514f5e3Sopenharmony_ci            JSHandle<LayoutInfo> old(thread, parentHClass->GetLayout());
16504514f5e3Sopenharmony_ci            for (uint32_t i = 0; i < parentLength; i++) {
16514514f5e3Sopenharmony_ci                key.Update(old->GetKey(i));
16524514f5e3Sopenharmony_ci                JSHandle<NameDictionary> newDict =
16534514f5e3Sopenharmony_ci                    NameDictionary::Put(thread, dict, key, value, PropertyAttributes(old->GetAttr(i)));
16544514f5e3Sopenharmony_ci                dict.Update(newDict);
16554514f5e3Sopenharmony_ci            }
16564514f5e3Sopenharmony_ci        }
16574514f5e3Sopenharmony_ci    }
16584514f5e3Sopenharmony_ci
16594514f5e3Sopenharmony_ci    hclass->SetLayout(thread, dict);
16604514f5e3Sopenharmony_ci    hclass->SetNumberOfProps(0);
16614514f5e3Sopenharmony_ci    hclass->SetIsDictionaryMode(true);
16624514f5e3Sopenharmony_ci}
16634514f5e3Sopenharmony_cibool JSHClass::IsNeedNotifyHclassChangedForAotTransition(const JSThread *thread, const JSHandle<JSHClass> &hclass,
16644514f5e3Sopenharmony_ci                                                         JSTaggedValue key)
16654514f5e3Sopenharmony_ci{
16664514f5e3Sopenharmony_ci    JSMutableHandle<JSObject> protoHandle(thread, hclass->GetPrototype());
16674514f5e3Sopenharmony_ci    while (protoHandle.GetTaggedValue().IsHeapObject()) {
16684514f5e3Sopenharmony_ci        JSHClass *protoHclass = protoHandle->GetJSHClass();
16694514f5e3Sopenharmony_ci        if (JSHClass::FindPropertyEntry(thread, protoHclass, key) != -1) {
16704514f5e3Sopenharmony_ci            return true;
16714514f5e3Sopenharmony_ci        }
16724514f5e3Sopenharmony_ci        protoHandle.Update(protoHclass->GetPrototype());
16734514f5e3Sopenharmony_ci    }
16744514f5e3Sopenharmony_ci    return false;
16754514f5e3Sopenharmony_ci}
16764514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
1677