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