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/js_symbol.h"
20 #include "ecmascript/global_dictionary.h"
21 #include "ecmascript/ic/property_box.h"
22 #include "ecmascript/mem/c_containers.h"
23 #include "ecmascript/tagged_hash_table.h"
24
25 namespace panda {
26 namespace ecmascript {
Hash(const JSTaggedValue & key)27 int GlobalDictionary::Hash(const JSTaggedValue &key)
28 {
29 if (key.IsHeapObject()) {
30 if (key.IsSymbol()) {
31 auto symbolString = JSSymbol::Cast(key.GetTaggedObject());
32 return symbolString->GetHashField();
33 }
34 if (key.IsString()) {
35 auto keyString = EcmaString::Cast(key.GetTaggedObject());
36 return EcmaStringAccessor(keyString).GetHashcode();
37 }
38 }
39 // key must be object
40 UNREACHABLE();
41 }
42
IsMatch(const JSTaggedValue & key,const JSTaggedValue & other)43 bool GlobalDictionary::IsMatch(const JSTaggedValue &key, const JSTaggedValue &other)
44 {
45 return key == other;
46 }
47
GetBox(int entry)48 PropertyBox *GlobalDictionary::GetBox(int entry) const
49 {
50 int index = GetEntryIndex(entry) + ENTRY_VALUE_INDEX;
51 return PropertyBox::Cast(Get(index).GetTaggedObject());
52 }
53
GetValue(int entry)54 JSTaggedValue GlobalDictionary::GetValue(int entry) const
55 {
56 return GetBox(entry)->GetValue();
57 }
58
GetAttributes(int entry)59 PropertyAttributes GlobalDictionary::GetAttributes(int entry) const
60 {
61 int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
62 return PropertyAttributes(Get(index).GetInt());
63 }
64
SetEntry(const JSThread * thread,int entry,const JSTaggedValue & key,const JSTaggedValue & value,const PropertyAttributes & attributes)65 void GlobalDictionary::SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value,
66 const PropertyAttributes &attributes)
67 {
68 SetKey(thread, entry, key);
69 SetAttributes(thread, entry, attributes);
70 UpdateValueAndAttributes(thread, entry, value, attributes);
71 }
72
ClearEntry(const JSThread * thread,int entry)73 void GlobalDictionary::ClearEntry(const JSThread *thread, int entry)
74 {
75 JSTaggedValue hole = JSTaggedValue::Hole();
76 PropertyAttributes metaData;
77 SetEntry(thread, entry, hole, hole, metaData);
78 }
79
UpdateValueAndAttributes(const JSThread * thread,int entry,const JSTaggedValue & value,const PropertyAttributes & metaData)80 void GlobalDictionary::UpdateValueAndAttributes(const JSThread *thread, int entry, const JSTaggedValue &value,
81 const PropertyAttributes &metaData)
82 {
83 UpdateValue(thread, entry, value);
84 SetAttributes(thread, entry, metaData);
85 }
86
SetAttributes(const JSThread * thread,int entry,const PropertyAttributes & metaData)87 void GlobalDictionary::SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData)
88 {
89 int index = static_cast<int>(GetEntryIndex(entry) + ENTRY_DETAILS_INDEX);
90 Set(thread, index, metaData.GetTaggedValue());
91 }
92
UpdateValue(const JSThread * thread,int entry,const JSTaggedValue & value)93 void GlobalDictionary::UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value)
94 {
95 SetValue(thread, entry, value);
96 }
97
GetAllKeys(const JSThread * thread,int offset,TaggedArray * keyArray)98 void GlobalDictionary::GetAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray) const
99 {
100 ASSERT_PRINT(offset + EntriesCount() <= static_cast<int>(keyArray->GetLength()),
101 "keyArray capacity is not enough for dictionary");
102 int arrayIndex = 0;
103 int size = Size();
104
105 CVector<std::pair<JSTaggedValue, uint32_t>> sortArr;
106 for (int hashIndex = 0; hashIndex < size; hashIndex++) {
107 JSTaggedValue key = GetKey(hashIndex);
108 if (!key.IsUndefined() && !key.IsHole()) {
109 PropertyAttributes attr = GetAttributes(hashIndex);
110 std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset());
111 sortArr.push_back(pair);
112 }
113 }
114 std::sort(sortArr.begin(), sortArr.end(), CompKey);
115 for (auto entry : sortArr) {
116 JSTaggedValue nameKey = entry.first;
117 keyArray->Set(thread, arrayIndex + offset, nameKey);
118 arrayIndex++;
119 }
120 }
121
GetEnumAllKeys(const JSThread * thread,int offset,TaggedArray * keyArray,uint32_t * keys)122 void GlobalDictionary::GetEnumAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray,
123 uint32_t *keys) const
124 {
125 ASSERT_PRINT(offset + EntriesCount() <= static_cast<int>(keyArray->GetLength()),
126 "keyArray capacity is not enough for dictionary");
127 int arrayIndex = 0;
128 int size = Size();
129
130 CVector<std::pair<JSTaggedValue, uint32_t>> sortArr;
131 for (int hashIndex = 0; hashIndex < size; hashIndex++) {
132 JSTaggedValue key = GetKey(hashIndex);
133 if (key.IsString()) {
134 PropertyAttributes attr = GetAttributes(hashIndex);
135 if (attr.IsEnumerable()) {
136 std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset());
137 sortArr.push_back(pair);
138 }
139 }
140 }
141 std::sort(sortArr.begin(), sortArr.end(), CompKey);
142 for (const auto &entry : sortArr) {
143 JSTaggedValue nameKey = entry.first;
144 keyArray->Set(thread, arrayIndex + offset, nameKey);
145 arrayIndex++;
146 }
147 *keys += arrayIndex;
148 }
149
CompKey(const std::pair<JSTaggedValue,uint32_t> & a,const std::pair<JSTaggedValue,uint32_t> & b)150 bool GlobalDictionary::CompKey(const std::pair<JSTaggedValue, uint32_t> &a, const std::pair<JSTaggedValue, uint32_t> &b)
151 {
152 return a.second < b.second;
153 }
154
InvalidatePropertyBox(JSThread * thread,const JSHandle<GlobalDictionary> & dictHandle,int entry,const PropertyAttributes & metaData)155 void GlobalDictionary::InvalidatePropertyBox(JSThread *thread, const JSHandle<GlobalDictionary> &dictHandle, int entry,
156 const PropertyAttributes &metaData)
157 {
158 PropertyBox *box = dictHandle->GetBox(entry);
159 PropertyAttributes originAttr = dictHandle->GetAttributes(entry);
160 PropertyAttributes newAttr(metaData);
161
162 ASSERT(!box->GetValue().IsHole());
163 int index = static_cast<int>(originAttr.GetDictionaryOrder());
164 JSHandle<JSTaggedValue> oldValue(thread, box->GetValue());
165 GlobalDictionary::InvalidateAndReplaceEntry(thread, dictHandle, index, oldValue);
166 dictHandle->SetAttributes(thread, entry, newAttr);
167 }
168
InvalidateAndReplaceEntry(JSThread * thread,const JSHandle<GlobalDictionary> & dictHandle,int entry,const JSHandle<JSTaggedValue> & oldValue)169 void GlobalDictionary::InvalidateAndReplaceEntry(JSThread *thread, const JSHandle<GlobalDictionary> &dictHandle,
170 int entry, const JSHandle<JSTaggedValue> &oldValue)
171 {
172 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
173 // Swap with a copy.
174 JSHandle<PropertyBox> newBox = factory->NewPropertyBox(oldValue);
175 PropertyBox *box = dictHandle->GetBox(entry);
176 PropertyAttributes attr = dictHandle->GetAttributes(entry);
177 ASSERT_PRINT(attr.IsConfigurable(), "property must be configurable");
178 ASSERT_PRINT(!box->GetValue().IsHole(), "value must not be hole");
179
180 // Cell is officially mutable henceforth.
181 attr.SetBoxType(PropertyBoxType::MUTABLE);
182 dictHandle->SetAttributes(thread, entry, attr);
183 dictHandle->UpdateValue(thread, entry, newBox.GetTaggedValue());
184 box->Clear(thread);
185 }
186 } // namespace ecmascript
187 } // namespace panda
188
189 #endif
190