1/* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#ifndef ECMASCRIPT_LAYOUT_INFO_INL_H 17#define ECMASCRIPT_LAYOUT_INFO_INL_H 18 19#include "ecmascript/layout_info.h" 20 21#include "ecmascript/ic/properties_cache.h" 22#include "ecmascript/js_thread.h" 23 24namespace panda::ecmascript { 25inline int LayoutInfo::GetPropertiesCapacity() const 26{ 27 return static_cast<int>((GetLength()) >> ELEMENTS_INDEX_LOG2); 28} 29 30inline int LayoutInfo::NumberOfElements() const 31{ 32 return GetExtraLength(); 33} 34 35inline void LayoutInfo::SetNumberOfElements([[maybe_unused]] const JSThread *thread, int properties) 36{ 37 SetExtraLength(properties); 38} 39 40inline uint32_t LayoutInfo::GetKeyIndex(int index) const 41{ 42 return static_cast<uint32_t>(index) << ELEMENTS_INDEX_LOG2; 43} 44 45inline uint32_t LayoutInfo::GetAttrIndex(int index) const 46{ 47 return (static_cast<uint32_t>(index) << ELEMENTS_INDEX_LOG2) + ATTR_INDEX_OFFSET; 48} 49 50inline void LayoutInfo::SetWithoutBarrier(uint32_t idx, const JSTaggedValue &value) 51{ 52 ASSERT(idx < GetLength()); 53 ASSERT(!value.IsHeapObject()); 54 size_t offset = JSTaggedValue::TaggedTypeSize() * idx; 55 56 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, value.GetRawData()); 57} 58 59inline void LayoutInfo::SetPropertyInit(const JSThread *thread, int index, const JSTaggedValue &key, 60 const PropertyAttributes &attr) 61{ 62 uint32_t fixedIdx = GetKeyIndex(index); 63 TaggedArray::Set(thread, fixedIdx, key); 64 TaggedArray::Set(thread, fixedIdx + ATTR_INDEX_OFFSET, attr.GetNormalTagged()); 65} 66 67inline void LayoutInfo::SetNormalAttr(const JSThread *thread, int index, const PropertyAttributes &attr) 68{ 69 uint32_t fixedIdx = GetAttrIndex(index); 70 PropertyAttributes oldAttr(TaggedArray::Get(fixedIdx)); 71 oldAttr.SetNormalAttr(attr.GetNormalAttr()); 72 TaggedArray::Set(thread, fixedIdx, oldAttr.GetTaggedValue()); 73} 74 75inline JSTaggedValue LayoutInfo::GetKey(int index) const 76{ 77 uint32_t fixedIdx = GetKeyIndex(index); 78 return TaggedArray::Get(fixedIdx); 79} 80 81inline PropertyAttributes LayoutInfo::GetAttr(int index) const 82{ 83 uint32_t fixedIdx = GetAttrIndex(index); 84 return PropertyAttributes(TaggedArray::Get(fixedIdx)); 85} 86 87inline JSTaggedValue LayoutInfo::GetSortedKey(int index) const 88{ 89 uint32_t fixedIdx = GetSortedIndex(index); 90 return GetKey(fixedIdx); 91} 92 93inline uint32_t LayoutInfo::GetSortedIndex(int index) const 94{ 95 return GetAttr(index).GetSortedIndex(); 96} 97 98inline void LayoutInfo::SetSortedIndex(const JSThread *thread, int index, int sortedIndex) 99{ 100 uint32_t fixedIdx = GetAttrIndex(index); 101 PropertyAttributes attr(TaggedArray::Get(fixedIdx)); 102 attr.SetSortedIndex(sortedIndex); 103 TaggedArray::Set(thread, fixedIdx, attr.GetTaggedValue()); 104} 105 106inline int LayoutInfo::FindElementWithCache(const JSThread *thread, JSHClass *cls, JSTaggedValue key, 107 int propertiesNumber) 108{ 109 ASSERT(NumberOfElements() >= propertiesNumber); 110 const int MAX_ELEMENTS_LINER_SEARCH = 9; // 9: Builtins Object properties number is nine; 111 if (propertiesNumber <= MAX_ELEMENTS_LINER_SEARCH) { 112 Span<struct Properties> sp(GetProperties(), propertiesNumber); 113 for (int i = 0; i < propertiesNumber; i++) { 114 if (sp[i].key_ == key) { 115 return i; 116 } 117 } 118 return -1; 119 } 120 121 // jit compile thread not use cache 122 if (thread->IsJitThread()) { 123 return BinarySearch(key, propertiesNumber); 124 } 125 126 PropertiesCache *cache = thread->GetPropertiesCache(); 127 int index = cache->Get(cls, key); 128 if (index == PropertiesCache::NOT_FOUND) { 129 index = BinarySearch(key, propertiesNumber); 130 if (index != -1) { 131 cache->Set(cls, key, index); 132 } 133 } 134 return index; 135} 136 137inline int LayoutInfo::BinarySearch(JSTaggedValue key, int propertiesNumber) 138{ 139 ASSERT(NumberOfElements() >= propertiesNumber); 140 int low = 0; 141 int elements = NumberOfElements(); 142 int high = elements - 1; 143 uint32_t keyHash = key.GetKeyHashCode(); 144 145 ASSERT(low <= high); 146 147 while (low <= high) { 148 int mid = low + (high - low) / 2; // 2: half 149 JSTaggedValue midKey = GetSortedKey(mid); 150 uint32_t midHash = midKey.GetKeyHashCode(); 151 if (midHash > keyHash) { 152 high = mid - 1; 153 } else if (midHash < keyHash) { 154 low = mid + 1; 155 } else { 156 int sortIndex = static_cast<int>(GetSortedIndex(mid)); 157 JSTaggedValue currentKey = GetKey(sortIndex); 158 if (currentKey == key) { 159 return sortIndex < propertiesNumber ? sortIndex : -1; 160 } 161 int midLeft = mid; 162 int midRight = mid; 163 while (midLeft - 1 >= 0) { 164 sortIndex = static_cast<int>(GetSortedIndex(--midLeft)); 165 currentKey = GetKey(sortIndex); 166 if (currentKey.GetKeyHashCode() == keyHash) { 167 if (currentKey == key) { 168 return sortIndex < propertiesNumber ? sortIndex : -1; 169 } 170 } else { 171 break; 172 } 173 } 174 while (midRight + 1 < elements) { 175 sortIndex = static_cast<int>(GetSortedIndex(++midRight)); 176 currentKey = GetKey(sortIndex); 177 if (currentKey.GetKeyHashCode() == keyHash) { 178 if (currentKey == key) { 179 return sortIndex < propertiesNumber ? sortIndex : -1; 180 } 181 } else { 182 break; 183 } 184 } 185 return -1; 186 } 187 } 188 return -1; 189} 190 191inline void LayoutInfo::SetIsNotHole(const JSThread *thread, int index) 192{ 193 uint32_t fixedIdx = GetAttrIndex(index); 194 PropertyAttributes attr(TaggedArray::Get(fixedIdx)); 195 attr.SetIsNotHole(true); 196 TaggedArray::Set(thread, fixedIdx, attr.GetTaggedValue()); 197} 198 199inline void LayoutInfo::UpdateTrackTypeAttr(int index, const PropertyAttributes &attr) 200{ 201 uint32_t fixedIdx = GetAttrIndex(index); 202 PropertyAttributes oldAttr(TaggedArray::Get(fixedIdx)); 203 oldAttr.SetNormalAttr(attr.GetNormalAttr()); 204 oldAttr.SetIsPGODumped(false); 205 SetWithoutBarrier(fixedIdx, oldAttr.GetTaggedValue()); 206} 207 208inline void LayoutInfo::SetIsPGODumped(int index) 209{ 210 uint32_t fixedIdx = GetAttrIndex(index); 211 PropertyAttributes attr(TaggedArray::Get(fixedIdx)); 212 attr.SetIsPGODumped(true); 213 SetWithoutBarrier(fixedIdx, attr.GetTaggedValue()); 214} 215 216template<bool checkDuplicateKeys /* = false*/> 217void LayoutInfo::AddKey(const JSThread *thread, [[maybe_unused]] int index, const JSTaggedValue &key, 218 const PropertyAttributes &attr) 219{ 220 DISALLOW_GARBAGE_COLLECTION; 221 int number = NumberOfElements(); 222 ASSERT(attr.GetOffset() == static_cast<uint32_t>(number)); 223 ASSERT(number + 1 <= GetPropertiesCapacity()); 224 ASSERT(number == index); 225 SetNumberOfElements(thread, number + 1); 226 SetPropertyInit(thread, number, key, attr); 227 228 uint32_t keyHash = key.GetKeyHashCode(); 229 int insertIndex = number; 230 for (; insertIndex > 0; --insertIndex) { 231 JSTaggedValue prevKey = GetSortedKey(insertIndex - 1); 232 if (prevKey.GetKeyHashCode() <= keyHash) { 233 break; 234 } 235 SetSortedIndex(thread, insertIndex, GetSortedIndex(insertIndex - 1)); 236 } 237 SetSortedIndex(thread, insertIndex, number); 238 if constexpr (checkDuplicateKeys) { 239 while (insertIndex > 0) { 240 JSTaggedValue prevKey = GetSortedKey(--insertIndex); 241 if (prevKey.GetKeyHashCode() < keyHash) { 242 return; 243 } 244 if (prevKey == key) { 245 THROW_TYPE_ERROR(const_cast<JSThread *>(thread), "property keys can not duplicate"); 246 } 247 } 248 } 249} 250} // namespace panda::ecmascript 251#endif // ECMASCRIPT_LAYOUT_INFO_INL_H 252