• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
26 namespace panda {
27 namespace ecmascript {
Hash(const JSTaggedValue & key)28 int 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 
IsMatch(const JSTaggedValue & key,const JSTaggedValue & other)45 bool GlobalDictionary::IsMatch(const JSTaggedValue &key, const JSTaggedValue &other)
46 {
47     return key == other;
48 }
49 
GetBox(int entry)50 PropertyBox *GlobalDictionary::GetBox(int entry) const
51 {
52     int index = GetEntryIndex(entry) + ENTRY_VALUE_INDEX;
53     return PropertyBox::Cast(Get(index).GetTaggedObject());
54 }
55 
GetValue(int entry)56 JSTaggedValue GlobalDictionary::GetValue(int entry) const
57 {
58     return GetBox(entry)->GetValue();
59 }
60 
GetAttributes(int entry)61 PropertyAttributes GlobalDictionary::GetAttributes(int entry) const
62 {
63     int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
64     return PropertyAttributes(Get(index));
65 }
66 
SetEntry(const JSThread * thread,int entry,const JSTaggedValue & key,const JSTaggedValue & value,const PropertyAttributes & attributes)67 void 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 
ClearEntry(const JSThread * thread,int entry)75 void 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 
UpdateValueAndAttributes(const JSThread * thread,int entry,const JSTaggedValue & value,const PropertyAttributes & metaData)82 void 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 
SetAttributes(const JSThread * thread,int entry,const PropertyAttributes & metaData)89 void 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 
UpdateValue(const JSThread * thread,int entry,const JSTaggedValue & value)95 void GlobalDictionary::UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value)
96 {
97     SetValue(thread, entry, value);
98 }
99 
GetAllKeys(const JSThread * thread,int offset,TaggedArray * keyArray)100 void 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 
GetAllKeysByFilter(const JSThread * thread,uint32_t & keyArrayEffectivelength,TaggedArray * keyArray,uint32_t filter)124 void 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 
GetNumOfEnumKeys()158 std::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 
GetEnumAllKeys(const JSThread * thread,int offset,TaggedArray * keyArray,uint32_t * keys)177 void 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 
CompKey(const std::pair<JSTaggedValue,uint32_t> & a,const std::pair<JSTaggedValue,uint32_t> & b)205 bool 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 
InvalidatePropertyBox(JSThread * thread,const JSHandle<GlobalDictionary> & dictHandle,int entry)210 void 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 
InvalidateAndReplaceEntry(JSThread * thread,const JSHandle<GlobalDictionary> & dictHandle,int entry,const JSHandle<JSTaggedValue> & oldValue)219 void 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 
IsValidateBox(int entry)243 bool 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