• 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/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