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