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, ®isterIndex); 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