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