14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021 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#ifndef ECMASCRIPT_GLOBAL_DICTIONARY_INL_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_GLOBAL_DICTIONARY_INL_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include "ecmascript/filter_helper.h" 204514f5e3Sopenharmony_ci#include "ecmascript/js_symbol.h" 214514f5e3Sopenharmony_ci#include "ecmascript/global_dictionary.h" 224514f5e3Sopenharmony_ci#include "ecmascript/ic/property_box.h" 234514f5e3Sopenharmony_ci#include "ecmascript/mem/c_containers.h" 244514f5e3Sopenharmony_ci#include "ecmascript/tagged_hash_table.h" 254514f5e3Sopenharmony_ci 264514f5e3Sopenharmony_cinamespace panda { 274514f5e3Sopenharmony_cinamespace ecmascript { 284514f5e3Sopenharmony_ciint GlobalDictionary::Hash(const JSTaggedValue &key) 294514f5e3Sopenharmony_ci{ 304514f5e3Sopenharmony_ci if (key.IsHeapObject()) { 314514f5e3Sopenharmony_ci if (key.IsSymbol()) { 324514f5e3Sopenharmony_ci auto symbolString = JSSymbol::Cast(key.GetTaggedObject()); 334514f5e3Sopenharmony_ci return symbolString->GetHashField(); 344514f5e3Sopenharmony_ci } 354514f5e3Sopenharmony_ci if (key.IsString()) { 364514f5e3Sopenharmony_ci auto keyString = EcmaString::Cast(key.GetTaggedObject()); 374514f5e3Sopenharmony_ci return EcmaStringAccessor(keyString).GetHashcode(); 384514f5e3Sopenharmony_ci } 394514f5e3Sopenharmony_ci } 404514f5e3Sopenharmony_ci // key must be object 414514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 424514f5e3Sopenharmony_ci UNREACHABLE(); 434514f5e3Sopenharmony_ci} 444514f5e3Sopenharmony_ci 454514f5e3Sopenharmony_cibool GlobalDictionary::IsMatch(const JSTaggedValue &key, const JSTaggedValue &other) 464514f5e3Sopenharmony_ci{ 474514f5e3Sopenharmony_ci return key == other; 484514f5e3Sopenharmony_ci} 494514f5e3Sopenharmony_ci 504514f5e3Sopenharmony_ciPropertyBox *GlobalDictionary::GetBox(int entry) const 514514f5e3Sopenharmony_ci{ 524514f5e3Sopenharmony_ci int index = GetEntryIndex(entry) + ENTRY_VALUE_INDEX; 534514f5e3Sopenharmony_ci return PropertyBox::Cast(Get(index).GetTaggedObject()); 544514f5e3Sopenharmony_ci} 554514f5e3Sopenharmony_ci 564514f5e3Sopenharmony_ciJSTaggedValue GlobalDictionary::GetValue(int entry) const 574514f5e3Sopenharmony_ci{ 584514f5e3Sopenharmony_ci return GetBox(entry)->GetValue(); 594514f5e3Sopenharmony_ci} 604514f5e3Sopenharmony_ci 614514f5e3Sopenharmony_ciPropertyAttributes GlobalDictionary::GetAttributes(int entry) const 624514f5e3Sopenharmony_ci{ 634514f5e3Sopenharmony_ci int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX; 644514f5e3Sopenharmony_ci return PropertyAttributes(Get(index)); 654514f5e3Sopenharmony_ci} 664514f5e3Sopenharmony_ci 674514f5e3Sopenharmony_civoid GlobalDictionary::SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value, 684514f5e3Sopenharmony_ci const PropertyAttributes &attributes) 694514f5e3Sopenharmony_ci{ 704514f5e3Sopenharmony_ci SetKey(thread, entry, key); 714514f5e3Sopenharmony_ci SetAttributes(thread, entry, attributes); 724514f5e3Sopenharmony_ci UpdateValueAndAttributes(thread, entry, value, attributes); 734514f5e3Sopenharmony_ci} 744514f5e3Sopenharmony_ci 754514f5e3Sopenharmony_civoid GlobalDictionary::ClearEntry(const JSThread *thread, int entry) 764514f5e3Sopenharmony_ci{ 774514f5e3Sopenharmony_ci JSTaggedValue hole = JSTaggedValue::Hole(); 784514f5e3Sopenharmony_ci PropertyAttributes metaData; 794514f5e3Sopenharmony_ci SetEntry(thread, entry, hole, hole, metaData); 804514f5e3Sopenharmony_ci} 814514f5e3Sopenharmony_ci 824514f5e3Sopenharmony_civoid GlobalDictionary::UpdateValueAndAttributes(const JSThread *thread, int entry, const JSTaggedValue &value, 834514f5e3Sopenharmony_ci const PropertyAttributes &metaData) 844514f5e3Sopenharmony_ci{ 854514f5e3Sopenharmony_ci UpdateValue(thread, entry, value); 864514f5e3Sopenharmony_ci SetAttributes(thread, entry, metaData); 874514f5e3Sopenharmony_ci} 884514f5e3Sopenharmony_ci 894514f5e3Sopenharmony_civoid GlobalDictionary::SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData) 904514f5e3Sopenharmony_ci{ 914514f5e3Sopenharmony_ci int index = static_cast<int>(GetEntryIndex(entry) + ENTRY_DETAILS_INDEX); 924514f5e3Sopenharmony_ci Set(thread, index, metaData.GetTaggedValue()); 934514f5e3Sopenharmony_ci} 944514f5e3Sopenharmony_ci 954514f5e3Sopenharmony_civoid GlobalDictionary::UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value) 964514f5e3Sopenharmony_ci{ 974514f5e3Sopenharmony_ci SetValue(thread, entry, value); 984514f5e3Sopenharmony_ci} 994514f5e3Sopenharmony_ci 1004514f5e3Sopenharmony_civoid GlobalDictionary::GetAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray) const 1014514f5e3Sopenharmony_ci{ 1024514f5e3Sopenharmony_ci ASSERT_PRINT(offset + EntriesCount() <= static_cast<int>(keyArray->GetLength()), 1034514f5e3Sopenharmony_ci "keyArray capacity is not enough for dictionary"); 1044514f5e3Sopenharmony_ci int arrayIndex = 0; 1054514f5e3Sopenharmony_ci int size = Size(); 1064514f5e3Sopenharmony_ci 1074514f5e3Sopenharmony_ci CVector<std::pair<JSTaggedValue, uint32_t>> sortArr; 1084514f5e3Sopenharmony_ci for (int hashIndex = 0; hashIndex < size; hashIndex++) { 1094514f5e3Sopenharmony_ci JSTaggedValue key = GetKey(hashIndex); 1104514f5e3Sopenharmony_ci if (!key.IsUndefined() && !key.IsHole()) { 1114514f5e3Sopenharmony_ci PropertyAttributes attr = GetAttributes(hashIndex); 1124514f5e3Sopenharmony_ci std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset()); 1134514f5e3Sopenharmony_ci sortArr.push_back(pair); 1144514f5e3Sopenharmony_ci } 1154514f5e3Sopenharmony_ci } 1164514f5e3Sopenharmony_ci std::sort(sortArr.begin(), sortArr.end(), CompKey); 1174514f5e3Sopenharmony_ci for (auto entry : sortArr) { 1184514f5e3Sopenharmony_ci JSTaggedValue nameKey = entry.first; 1194514f5e3Sopenharmony_ci keyArray->Set(thread, arrayIndex + offset, nameKey); 1204514f5e3Sopenharmony_ci arrayIndex++; 1214514f5e3Sopenharmony_ci } 1224514f5e3Sopenharmony_ci} 1234514f5e3Sopenharmony_ci 1244514f5e3Sopenharmony_civoid GlobalDictionary::GetAllKeysByFilter(const JSThread *thread, 1254514f5e3Sopenharmony_ci uint32_t &keyArrayEffectivelength, TaggedArray *keyArray, uint32_t filter) const 1264514f5e3Sopenharmony_ci{ 1274514f5e3Sopenharmony_ci ASSERT_PRINT(keyArrayEffectivelength + static_cast<uint32_t>(EntriesCount()) <= keyArray->GetLength(), 1284514f5e3Sopenharmony_ci "keyArray capacity is not enough for dictionary"); 1294514f5e3Sopenharmony_ci int size = Size(); 1304514f5e3Sopenharmony_ci 1314514f5e3Sopenharmony_ci CVector<std::pair<JSTaggedValue, uint32_t>> sortArr; 1324514f5e3Sopenharmony_ci for (int hashIndex = 0; hashIndex < size; hashIndex++) { 1334514f5e3Sopenharmony_ci JSTaggedValue key = GetKey(hashIndex); 1344514f5e3Sopenharmony_ci if (!key.IsUndefined() && !key.IsHole()) { 1354514f5e3Sopenharmony_ci PropertyAttributes attr = GetAttributes(hashIndex); 1364514f5e3Sopenharmony_ci bool bIgnore = FilterHelper::IgnoreKeyByFilter<PropertyAttributes>(attr, filter); 1374514f5e3Sopenharmony_ci if (bIgnore) { 1384514f5e3Sopenharmony_ci continue; 1394514f5e3Sopenharmony_ci } 1404514f5e3Sopenharmony_ci if (key.IsString() && (filter & NATIVE_KEY_SKIP_STRINGS)) { 1414514f5e3Sopenharmony_ci continue; 1424514f5e3Sopenharmony_ci } 1434514f5e3Sopenharmony_ci if (key.IsSymbol() && (filter & NATIVE_KEY_SKIP_SYMBOLS)) { 1444514f5e3Sopenharmony_ci continue; 1454514f5e3Sopenharmony_ci } 1464514f5e3Sopenharmony_ci std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset()); 1474514f5e3Sopenharmony_ci sortArr.push_back(pair); 1484514f5e3Sopenharmony_ci } 1494514f5e3Sopenharmony_ci } 1504514f5e3Sopenharmony_ci std::sort(sortArr.begin(), sortArr.end(), CompKey); 1514514f5e3Sopenharmony_ci for (auto entry : sortArr) { 1524514f5e3Sopenharmony_ci JSTaggedValue nameKey = entry.first; 1534514f5e3Sopenharmony_ci keyArray->Set(thread, keyArrayEffectivelength, nameKey); 1544514f5e3Sopenharmony_ci keyArrayEffectivelength++; 1554514f5e3Sopenharmony_ci } 1564514f5e3Sopenharmony_ci} 1574514f5e3Sopenharmony_ci 1584514f5e3Sopenharmony_cistd::pair<uint32_t, uint32_t> GlobalDictionary::GetNumOfEnumKeys() const 1594514f5e3Sopenharmony_ci{ 1604514f5e3Sopenharmony_ci uint32_t enumKeys = 0; 1614514f5e3Sopenharmony_ci uint32_t shadowKeys = 0; 1624514f5e3Sopenharmony_ci int size = Size(); 1634514f5e3Sopenharmony_ci for (int hashIndex = 0; hashIndex < size; hashIndex++) { 1644514f5e3Sopenharmony_ci JSTaggedValue key = GetKey(hashIndex); 1654514f5e3Sopenharmony_ci if (key.IsString()) { 1664514f5e3Sopenharmony_ci PropertyAttributes attr = GetAttributes(hashIndex); 1674514f5e3Sopenharmony_ci if (attr.IsEnumerable()) { 1684514f5e3Sopenharmony_ci enumKeys++; 1694514f5e3Sopenharmony_ci } else { 1704514f5e3Sopenharmony_ci shadowKeys++; 1714514f5e3Sopenharmony_ci } 1724514f5e3Sopenharmony_ci } 1734514f5e3Sopenharmony_ci } 1744514f5e3Sopenharmony_ci return std::make_pair(enumKeys, shadowKeys); 1754514f5e3Sopenharmony_ci} 1764514f5e3Sopenharmony_ci 1774514f5e3Sopenharmony_civoid GlobalDictionary::GetEnumAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray, 1784514f5e3Sopenharmony_ci uint32_t *keys) const 1794514f5e3Sopenharmony_ci{ 1804514f5e3Sopenharmony_ci ASSERT_PRINT(offset + GetNumOfEnumKeys().first <= static_cast<unsigned int>(keyArray->GetLength()), 1814514f5e3Sopenharmony_ci "keyArray capacity is not enough for dictionary"); 1824514f5e3Sopenharmony_ci int arrayIndex = 0; 1834514f5e3Sopenharmony_ci int size = Size(); 1844514f5e3Sopenharmony_ci 1854514f5e3Sopenharmony_ci CVector<std::pair<JSTaggedValue, uint32_t>> sortArr; 1864514f5e3Sopenharmony_ci for (int hashIndex = 0; hashIndex < size; hashIndex++) { 1874514f5e3Sopenharmony_ci JSTaggedValue key = GetKey(hashIndex); 1884514f5e3Sopenharmony_ci if (key.IsString()) { 1894514f5e3Sopenharmony_ci PropertyAttributes attr = GetAttributes(hashIndex); 1904514f5e3Sopenharmony_ci if (attr.IsEnumerable()) { 1914514f5e3Sopenharmony_ci std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset()); 1924514f5e3Sopenharmony_ci sortArr.push_back(pair); 1934514f5e3Sopenharmony_ci } 1944514f5e3Sopenharmony_ci } 1954514f5e3Sopenharmony_ci } 1964514f5e3Sopenharmony_ci std::sort(sortArr.begin(), sortArr.end(), CompKey); 1974514f5e3Sopenharmony_ci for (const auto &entry : sortArr) { 1984514f5e3Sopenharmony_ci JSTaggedValue nameKey = entry.first; 1994514f5e3Sopenharmony_ci keyArray->Set(thread, arrayIndex + offset, nameKey); 2004514f5e3Sopenharmony_ci arrayIndex++; 2014514f5e3Sopenharmony_ci } 2024514f5e3Sopenharmony_ci *keys += arrayIndex; 2034514f5e3Sopenharmony_ci} 2044514f5e3Sopenharmony_ci 2054514f5e3Sopenharmony_cibool GlobalDictionary::CompKey(const std::pair<JSTaggedValue, uint32_t> &a, const std::pair<JSTaggedValue, uint32_t> &b) 2064514f5e3Sopenharmony_ci{ 2074514f5e3Sopenharmony_ci return a.second < b.second; 2084514f5e3Sopenharmony_ci} 2094514f5e3Sopenharmony_ci 2104514f5e3Sopenharmony_civoid GlobalDictionary::InvalidatePropertyBox(JSThread *thread, const JSHandle<GlobalDictionary> &dictHandle, int entry) 2114514f5e3Sopenharmony_ci{ 2124514f5e3Sopenharmony_ci PropertyBox *box = dictHandle->GetBox(entry); 2134514f5e3Sopenharmony_ci 2144514f5e3Sopenharmony_ci ASSERT(!box->GetValue().IsHole()); 2154514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> oldValue(thread, box->GetValue()); 2164514f5e3Sopenharmony_ci GlobalDictionary::InvalidateAndReplaceEntry(thread, dictHandle, entry, oldValue); 2174514f5e3Sopenharmony_ci} 2184514f5e3Sopenharmony_ci 2194514f5e3Sopenharmony_civoid GlobalDictionary::InvalidateAndReplaceEntry(JSThread *thread, const JSHandle<GlobalDictionary> &dictHandle, 2204514f5e3Sopenharmony_ci int entry, const JSHandle<JSTaggedValue> &oldValue) 2214514f5e3Sopenharmony_ci{ 2224514f5e3Sopenharmony_ci if (!dictHandle->IsValidateBox(entry)) { 2234514f5e3Sopenharmony_ci return; 2244514f5e3Sopenharmony_ci } 2254514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 2264514f5e3Sopenharmony_ci // Swap with a copy. 2274514f5e3Sopenharmony_ci JSHandle<PropertyBox> newBox = factory->NewPropertyBox(oldValue); 2284514f5e3Sopenharmony_ci PropertyBox *box = dictHandle->GetBox(entry); 2294514f5e3Sopenharmony_ci PropertyAttributes attr = dictHandle->GetAttributes(entry); 2304514f5e3Sopenharmony_ci if (!attr.IsConfigurable() || box->GetValue().IsHole()) { 2314514f5e3Sopenharmony_ci return; 2324514f5e3Sopenharmony_ci } 2334514f5e3Sopenharmony_ci ASSERT_PRINT(attr.IsConfigurable(), "property must be configurable"); 2344514f5e3Sopenharmony_ci ASSERT_PRINT(!box->GetValue().IsHole(), "value must not be hole"); 2354514f5e3Sopenharmony_ci 2364514f5e3Sopenharmony_ci // Cell is officially mutable henceforth. 2374514f5e3Sopenharmony_ci attr.SetBoxType(PropertyBoxType::MUTABLE); 2384514f5e3Sopenharmony_ci dictHandle->SetAttributes(thread, entry, attr); 2394514f5e3Sopenharmony_ci dictHandle->UpdateValue(thread, entry, newBox.GetTaggedValue()); 2404514f5e3Sopenharmony_ci box->Clear(thread); 2414514f5e3Sopenharmony_ci} 2424514f5e3Sopenharmony_ci 2434514f5e3Sopenharmony_cibool GlobalDictionary::IsValidateBox(int entry) const 2444514f5e3Sopenharmony_ci{ 2454514f5e3Sopenharmony_ci int index = GetEntryIndex(entry) + ENTRY_VALUE_INDEX; 2464514f5e3Sopenharmony_ci return !Get(index).IsUndefined(); 2474514f5e3Sopenharmony_ci} 2484514f5e3Sopenharmony_ci} // namespace ecmascript 2494514f5e3Sopenharmony_ci} // namespace panda 2504514f5e3Sopenharmony_ci 2514514f5e3Sopenharmony_ci#endif 252