1/* 2 * Copyright (c) 2021 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_GLOBAL_DICTIONARY_INL_H 17#define ECMASCRIPT_GLOBAL_DICTIONARY_INL_H 18 19#include "ecmascript/filter_helper.h" 20#include "ecmascript/js_symbol.h" 21#include "ecmascript/global_dictionary.h" 22#include "ecmascript/ic/property_box.h" 23#include "ecmascript/mem/c_containers.h" 24#include "ecmascript/tagged_hash_table.h" 25 26namespace panda { 27namespace ecmascript { 28int GlobalDictionary::Hash(const JSTaggedValue &key) 29{ 30 if (key.IsHeapObject()) { 31 if (key.IsSymbol()) { 32 auto symbolString = JSSymbol::Cast(key.GetTaggedObject()); 33 return symbolString->GetHashField(); 34 } 35 if (key.IsString()) { 36 auto keyString = EcmaString::Cast(key.GetTaggedObject()); 37 return EcmaStringAccessor(keyString).GetHashcode(); 38 } 39 } 40 // key must be object 41 LOG_ECMA(FATAL) << "this branch is unreachable"; 42 UNREACHABLE(); 43} 44 45bool GlobalDictionary::IsMatch(const JSTaggedValue &key, const JSTaggedValue &other) 46{ 47 return key == other; 48} 49 50PropertyBox *GlobalDictionary::GetBox(int entry) const 51{ 52 int index = GetEntryIndex(entry) + ENTRY_VALUE_INDEX; 53 return PropertyBox::Cast(Get(index).GetTaggedObject()); 54} 55 56JSTaggedValue GlobalDictionary::GetValue(int entry) const 57{ 58 return GetBox(entry)->GetValue(); 59} 60 61PropertyAttributes GlobalDictionary::GetAttributes(int entry) const 62{ 63 int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX; 64 return PropertyAttributes(Get(index)); 65} 66 67void GlobalDictionary::SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value, 68 const PropertyAttributes &attributes) 69{ 70 SetKey(thread, entry, key); 71 SetAttributes(thread, entry, attributes); 72 UpdateValueAndAttributes(thread, entry, value, attributes); 73} 74 75void GlobalDictionary::ClearEntry(const JSThread *thread, int entry) 76{ 77 JSTaggedValue hole = JSTaggedValue::Hole(); 78 PropertyAttributes metaData; 79 SetEntry(thread, entry, hole, hole, metaData); 80} 81 82void GlobalDictionary::UpdateValueAndAttributes(const JSThread *thread, int entry, const JSTaggedValue &value, 83 const PropertyAttributes &metaData) 84{ 85 UpdateValue(thread, entry, value); 86 SetAttributes(thread, entry, metaData); 87} 88 89void GlobalDictionary::SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData) 90{ 91 int index = static_cast<int>(GetEntryIndex(entry) + ENTRY_DETAILS_INDEX); 92 Set(thread, index, metaData.GetTaggedValue()); 93} 94 95void GlobalDictionary::UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value) 96{ 97 SetValue(thread, entry, value); 98} 99 100void GlobalDictionary::GetAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray) const 101{ 102 ASSERT_PRINT(offset + EntriesCount() <= static_cast<int>(keyArray->GetLength()), 103 "keyArray capacity is not enough for dictionary"); 104 int arrayIndex = 0; 105 int size = Size(); 106 107 CVector<std::pair<JSTaggedValue, uint32_t>> sortArr; 108 for (int hashIndex = 0; hashIndex < size; hashIndex++) { 109 JSTaggedValue key = GetKey(hashIndex); 110 if (!key.IsUndefined() && !key.IsHole()) { 111 PropertyAttributes attr = GetAttributes(hashIndex); 112 std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset()); 113 sortArr.push_back(pair); 114 } 115 } 116 std::sort(sortArr.begin(), sortArr.end(), CompKey); 117 for (auto entry : sortArr) { 118 JSTaggedValue nameKey = entry.first; 119 keyArray->Set(thread, arrayIndex + offset, nameKey); 120 arrayIndex++; 121 } 122} 123 124void GlobalDictionary::GetAllKeysByFilter(const JSThread *thread, 125 uint32_t &keyArrayEffectivelength, TaggedArray *keyArray, uint32_t filter) const 126{ 127 ASSERT_PRINT(keyArrayEffectivelength + static_cast<uint32_t>(EntriesCount()) <= keyArray->GetLength(), 128 "keyArray capacity is not enough for dictionary"); 129 int size = Size(); 130 131 CVector<std::pair<JSTaggedValue, uint32_t>> sortArr; 132 for (int hashIndex = 0; hashIndex < size; hashIndex++) { 133 JSTaggedValue key = GetKey(hashIndex); 134 if (!key.IsUndefined() && !key.IsHole()) { 135 PropertyAttributes attr = GetAttributes(hashIndex); 136 bool bIgnore = FilterHelper::IgnoreKeyByFilter<PropertyAttributes>(attr, filter); 137 if (bIgnore) { 138 continue; 139 } 140 if (key.IsString() && (filter & NATIVE_KEY_SKIP_STRINGS)) { 141 continue; 142 } 143 if (key.IsSymbol() && (filter & NATIVE_KEY_SKIP_SYMBOLS)) { 144 continue; 145 } 146 std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset()); 147 sortArr.push_back(pair); 148 } 149 } 150 std::sort(sortArr.begin(), sortArr.end(), CompKey); 151 for (auto entry : sortArr) { 152 JSTaggedValue nameKey = entry.first; 153 keyArray->Set(thread, keyArrayEffectivelength, nameKey); 154 keyArrayEffectivelength++; 155 } 156} 157 158std::pair<uint32_t, uint32_t> GlobalDictionary::GetNumOfEnumKeys() const 159{ 160 uint32_t enumKeys = 0; 161 uint32_t shadowKeys = 0; 162 int size = Size(); 163 for (int hashIndex = 0; hashIndex < size; hashIndex++) { 164 JSTaggedValue key = GetKey(hashIndex); 165 if (key.IsString()) { 166 PropertyAttributes attr = GetAttributes(hashIndex); 167 if (attr.IsEnumerable()) { 168 enumKeys++; 169 } else { 170 shadowKeys++; 171 } 172 } 173 } 174 return std::make_pair(enumKeys, shadowKeys); 175} 176 177void GlobalDictionary::GetEnumAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray, 178 uint32_t *keys) const 179{ 180 ASSERT_PRINT(offset + GetNumOfEnumKeys().first <= static_cast<unsigned int>(keyArray->GetLength()), 181 "keyArray capacity is not enough for dictionary"); 182 int arrayIndex = 0; 183 int size = Size(); 184 185 CVector<std::pair<JSTaggedValue, uint32_t>> sortArr; 186 for (int hashIndex = 0; hashIndex < size; hashIndex++) { 187 JSTaggedValue key = GetKey(hashIndex); 188 if (key.IsString()) { 189 PropertyAttributes attr = GetAttributes(hashIndex); 190 if (attr.IsEnumerable()) { 191 std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset()); 192 sortArr.push_back(pair); 193 } 194 } 195 } 196 std::sort(sortArr.begin(), sortArr.end(), CompKey); 197 for (const auto &entry : sortArr) { 198 JSTaggedValue nameKey = entry.first; 199 keyArray->Set(thread, arrayIndex + offset, nameKey); 200 arrayIndex++; 201 } 202 *keys += arrayIndex; 203} 204 205bool GlobalDictionary::CompKey(const std::pair<JSTaggedValue, uint32_t> &a, const std::pair<JSTaggedValue, uint32_t> &b) 206{ 207 return a.second < b.second; 208} 209 210void GlobalDictionary::InvalidatePropertyBox(JSThread *thread, const JSHandle<GlobalDictionary> &dictHandle, int entry) 211{ 212 PropertyBox *box = dictHandle->GetBox(entry); 213 214 ASSERT(!box->GetValue().IsHole()); 215 JSHandle<JSTaggedValue> oldValue(thread, box->GetValue()); 216 GlobalDictionary::InvalidateAndReplaceEntry(thread, dictHandle, entry, oldValue); 217} 218 219void GlobalDictionary::InvalidateAndReplaceEntry(JSThread *thread, const JSHandle<GlobalDictionary> &dictHandle, 220 int entry, const JSHandle<JSTaggedValue> &oldValue) 221{ 222 if (!dictHandle->IsValidateBox(entry)) { 223 return; 224 } 225 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 226 // Swap with a copy. 227 JSHandle<PropertyBox> newBox = factory->NewPropertyBox(oldValue); 228 PropertyBox *box = dictHandle->GetBox(entry); 229 PropertyAttributes attr = dictHandle->GetAttributes(entry); 230 if (!attr.IsConfigurable() || box->GetValue().IsHole()) { 231 return; 232 } 233 ASSERT_PRINT(attr.IsConfigurable(), "property must be configurable"); 234 ASSERT_PRINT(!box->GetValue().IsHole(), "value must not be hole"); 235 236 // Cell is officially mutable henceforth. 237 attr.SetBoxType(PropertyBoxType::MUTABLE); 238 dictHandle->SetAttributes(thread, entry, attr); 239 dictHandle->UpdateValue(thread, entry, newBox.GetTaggedValue()); 240 box->Clear(thread); 241} 242 243bool GlobalDictionary::IsValidateBox(int entry) const 244{ 245 int index = GetEntryIndex(entry) + ENTRY_VALUE_INDEX; 246 return !Get(index).IsUndefined(); 247} 248} // namespace ecmascript 249} // namespace panda 250 251#endif 252