• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #include "ecmascript/tagged_dictionary.h"
17 #include "ecmascript/ecma_string-inl.h"
18 #include "ecmascript/js_object-inl.h"
19 
20 namespace panda::ecmascript {
Hash(const JSThread * thread,const JSTaggedValue & key)21 int NameDictionary::Hash(const JSThread *thread, const JSTaggedValue &key)
22 {
23     if (key.IsHeapObject()) {
24         JSTaggedValue jsKey(key);
25         if (jsKey.IsSymbol()) {
26             auto symbolString = JSSymbol::Cast(key.GetTaggedObject());
27             return symbolString->GetHashField();
28         }
29         if (jsKey.IsString()) {
30             auto keyString = reinterpret_cast<EcmaString *>(key.GetTaggedObject());
31             return EcmaStringAccessor(keyString).GetHashcode(thread);
32         }
33     }
34     // key must be object
35     LOG_ECMA(FATAL) << "this branch is unreachable";
36     UNREACHABLE();
37 }
38 
39 // for ohmurl path to compute hash code
Hash(const uint8_t * str,int strSize)40 int NameDictionary::Hash(const uint8_t* str, int strSize)
41 {
42     uint32_t hash = BaseString::ComputeHashForData(str, strSize, 0);
43     // url path can not be small int.
44     return BaseString::MixHashcode(hash, BaseString::NOT_INTEGER);
45 }
46 
IsMatch(const JSThread * thread,const JSTaggedValue & key,const JSTaggedValue & other)47 bool NameDictionary::IsMatch([[maybe_unused]] const JSThread *thread, const JSTaggedValue &key,
48                              const JSTaggedValue &other)
49 {
50     return key == other;
51 }
52 
IsMatch(const uint8_t * str,int size,const JSTaggedValue & other)53 bool NameDictionary::IsMatch(const uint8_t* str, int size, const JSTaggedValue &other)
54 {
55     if (!other.IsString()) {
56         return false;
57     }
58     EcmaString *keyString = reinterpret_cast<EcmaString *>(other.GetTaggedObject());
59 
60     Span<const uint8_t> data1(EcmaStringAccessor(keyString).GetDataUtf8(), keyString->GetLength());
61     Span<const uint8_t> data2(str, size);
62     if (data1.Size() != data2.Size()) {
63         return false;
64     }
65     return EcmaString::StringsAreEquals(data1, data2);
66 }
67 
GetAllKeys(const JSThread * thread,int offset,TaggedArray * keyArray) const68 void NameDictionary::GetAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray) const
69 {
70     int arrayIndex = 0;
71     int size = Size();
72     CVector<std::pair<JSTaggedValue, PropertyAttributes>> sortArr;
73     for (int hashIndex = 0; hashIndex < size; hashIndex++) {
74         JSTaggedValue key = GetKey(thread, hashIndex);
75         if (!key.IsUndefined() && !key.IsHole()) {
76             PropertyAttributes attr = GetAttributes(thread, hashIndex);
77             std::pair<JSTaggedValue, PropertyAttributes> pair(key, attr);
78             sortArr.push_back(pair);
79         }
80     }
81     std::sort(sortArr.begin(), sortArr.end(), CompKey);
82     for (const auto &entry : sortArr) {
83         keyArray->Set(thread, arrayIndex + offset, entry.first);
84         arrayIndex++;
85     }
86 }
87 
UpdateAllAttributesToNoWitable(const JSThread * thread)88 void NameDictionary::UpdateAllAttributesToNoWitable(const JSThread *thread)
89 {
90     int size = Size();
91     for (int hashIndex = 0; hashIndex < size; hashIndex++) {
92         JSTaggedValue key = GetKey(thread, hashIndex);
93         if (!key.IsUndefined() && !key.IsHole()) {
94             PropertyAttributes attr = GetAttributes(thread, hashIndex);
95             attr.SetWritable(false);
96             SetAttributes(thread, hashIndex, attr);
97         }
98     }
99 }
100 
GetAllKeysByFilter(const JSThread * thread,uint32_t & keyArrayEffectivelength,TaggedArray * keyArray,uint32_t filter) const101 void NameDictionary::GetAllKeysByFilter(const JSThread *thread, uint32_t &keyArrayEffectivelength,
102                                         TaggedArray *keyArray, uint32_t filter) const
103 {
104     int size = Size();
105     CVector<std::pair<JSTaggedValue, PropertyAttributes>> sortArr;
106     for (int hashIndex = 0; hashIndex < size; hashIndex++) {
107         JSTaggedValue key = GetKey(thread, hashIndex);
108         if (!key.IsUndefined() && !key.IsHole()) {
109             PropertyAttributes attr = GetAttributes(thread, hashIndex);
110             bool bIgnore = FilterHelper::IgnoreKeyByFilter<PropertyAttributes>(attr, filter);
111             if (bIgnore) {
112                 continue;
113             }
114             if (key.IsString() && (filter & NATIVE_KEY_SKIP_STRINGS)) {
115                 continue;
116             }
117             if (key.IsSymbol() && (filter & NATIVE_KEY_SKIP_SYMBOLS)) {
118                 continue;
119             }
120             std::pair<JSTaggedValue, PropertyAttributes> pair(key, attr);
121             sortArr.push_back(pair);
122         }
123     }
124     std::sort(sortArr.begin(), sortArr.end(), CompKey);
125     for (const auto &entry : sortArr) {
126         keyArray->Set(thread, keyArrayEffectivelength, entry.first);
127         keyArrayEffectivelength++;
128     }
129 }
130 
GetNumOfEnumKeys(const JSThread * thread) const131 std::pair<uint32_t, uint32_t> NameDictionary::GetNumOfEnumKeys(const JSThread *thread) const
132 {
133     uint32_t enumKeys = 0;
134     uint32_t shadowKeys = 0;
135     int size = Size();
136     for (int hashIndex = 0; hashIndex < size; hashIndex++) {
137         JSTaggedValue key = GetKey(thread, hashIndex);
138         if (key.IsString()) {
139             PropertyAttributes attr = GetAttributes(thread, hashIndex);
140             if (attr.IsEnumerable()) {
141                 enumKeys++;
142             } else {
143                 shadowKeys++;
144             }
145         }
146     }
147     return std::make_pair(enumKeys, shadowKeys);
148 }
149 
GetAllEnumKeys(JSThread * thread,int offset,JSHandle<TaggedArray> keyArray,uint32_t * keys,JSHandle<TaggedQueue> shadowQueue,int32_t lastLength) const150 void NameDictionary::GetAllEnumKeys(JSThread *thread, int offset, JSHandle<TaggedArray> keyArray, uint32_t *keys,
151                                     JSHandle<TaggedQueue> shadowQueue, int32_t lastLength) const
152 {
153     uint32_t arrayIndex = 0;
154     CVector<std::pair<JSHandle<JSTaggedValue>, PropertyAttributes>> sortArr;
155     int size = Size();
156     for (int hashIndex = 0; hashIndex < size; hashIndex++) {
157         JSHandle<JSTaggedValue> keyHandle(thread, GetKey(thread, hashIndex));
158         if (keyHandle->IsString()) {
159             PropertyAttributes attr = GetAttributes(thread, hashIndex);
160             if (attr.IsEnumerable()) {
161                 std::pair<JSHandle<JSTaggedValue>, PropertyAttributes> pair(keyHandle, attr);
162                 bool isDuplicated = JSObject::IsDepulicateKeys(thread, keyArray, lastLength, shadowQueue, keyHandle);
163                 if (isDuplicated) {
164                     continue;
165                 }
166                 sortArr.push_back(pair);
167             } else {
168                 TaggedQueue::PushFixedQueue(thread, shadowQueue, keyHandle);
169             }
170         }
171     }
172     std::sort(sortArr.begin(), sortArr.end(), CompHandleKey);
173     for (auto entry : sortArr) {
174         keyArray->Set(thread, arrayIndex + static_cast<uint32_t>(offset), entry.first);
175         arrayIndex++;
176     }
177     *keys += arrayIndex;
178 }
179 
GetAllEnumKeys(JSThread * thread,int offset,JSHandle<TaggedArray> keyArray,uint32_t * keys) const180 void NameDictionary::GetAllEnumKeys(JSThread *thread, int offset, JSHandle<TaggedArray> keyArray, uint32_t *keys) const
181 {
182     uint32_t arrayIndex = 0;
183     CVector<std::pair<JSHandle<JSTaggedValue>, PropertyAttributes>> sortArr;
184     int size = Size();
185     for (int hashIndex = 0; hashIndex < size; hashIndex++) {
186         JSHandle<JSTaggedValue> keyHandle(thread, GetKey(thread, hashIndex));
187         if (keyHandle->IsString()) {
188             PropertyAttributes attr = GetAttributes(thread, hashIndex);
189             if (attr.IsEnumerable()) {
190                 std::pair<JSHandle<JSTaggedValue>, PropertyAttributes> pair(keyHandle, attr);
191                 sortArr.push_back(pair);
192             }
193         }
194     }
195     std::sort(sortArr.begin(), sortArr.end(), CompHandleKey);
196     for (auto entry : sortArr) {
197         keyArray->Set(thread, arrayIndex + static_cast<uint32_t>(offset), entry.first);
198         arrayIndex++;
199     }
200     *keys += arrayIndex;
201 }
202 
Create(const JSThread * thread,int numberOfElements)203 JSHandle<NameDictionary> NameDictionary::Create(const JSThread *thread, int numberOfElements)
204 {
205     return OrderHashTableT::Create(thread, numberOfElements);
206 }
207 
CreateInSharedHeap(const JSThread * thread,int numberOfElements)208 JSHandle<NameDictionary> NameDictionary::CreateInSharedHeap(const JSThread *thread, int numberOfElements)
209 {
210     return OrderHashTableT::Create(thread, numberOfElements, MemSpaceKind::SHARED);
211 }
212 
GetAttributes(const JSThread * thread,int entry) const213 PropertyAttributes NameDictionary::GetAttributes(const JSThread *thread, int entry) const
214 {
215     int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
216     return PropertyAttributes(Get(thread, index));
217 }
218 
SetAttributes(const JSThread * thread,int entry,const PropertyAttributes & metaData)219 void NameDictionary::SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData)
220 {
221     int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
222     Set(thread, index, metaData.GetTaggedValue());
223 }
224 
SetEntry(const JSThread * thread,int entry,const JSTaggedValue & key,const JSTaggedValue & value,const PropertyAttributes & metaData)225 void NameDictionary::SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value,
226                               const PropertyAttributes &metaData)
227 {
228     SetKey(thread, entry, key);
229     SetValue(thread, entry, value);
230     SetAttributes(thread, entry, metaData);
231 }
232 
UpdateValueAndAttributes(const JSThread * thread,int entry,const JSTaggedValue & value,const PropertyAttributes & metaData)233 void NameDictionary::UpdateValueAndAttributes(const JSThread *thread, int entry, const JSTaggedValue &value,
234                                               const PropertyAttributes &metaData)
235 {
236     SetValue(thread, entry, value);
237     SetAttributes(thread, entry, metaData);
238 }
239 
UpdateValue(const JSThread * thread,int entry,const JSTaggedValue & value)240 void NameDictionary::UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value)
241 {
242     SetValue(thread, entry, value);
243 }
244 
ClearEntry(const JSThread * thread,int entry)245 void NameDictionary::ClearEntry(const JSThread *thread, int entry)
246 {
247     JSTaggedValue hole = JSTaggedValue::Hole();
248     PropertyAttributes metaData;
249     SetEntry(thread, entry, hole, hole, metaData);
250 }
251 
Hash(const JSThread * thread,const JSTaggedValue & key)252 int NumberDictionary::Hash([[maybe_unused]] const JSThread *thread, const JSTaggedValue &key)
253 {
254     if (key.IsInt()) {
255         int keyValue = key.GetInt();
256         return GetHash32(reinterpret_cast<uint8_t *>(&keyValue), sizeof(keyValue) / sizeof(uint8_t));
257     }
258     if (key.IsDouble()) {
259         int32_t keyValue = static_cast<int32_t>(static_cast<uint32_t>(key.GetDouble()));
260         return GetHash32(reinterpret_cast<uint8_t *>(&keyValue), sizeof(keyValue) / sizeof(uint8_t));
261     }
262     // key must be object
263     LOG_ECMA(FATAL) << "this branch is unreachable";
264     UNREACHABLE();
265 }
266 
IsMatch(const JSThread * thread,const JSTaggedValue & key,const JSTaggedValue & other)267 bool NumberDictionary::IsMatch([[maybe_unused]] const JSThread *thread, const JSTaggedValue &key,
268                                const JSTaggedValue &other)
269 {
270     if (key.IsHole() || key.IsUndefined()) {
271         return false;
272     }
273 
274     if (key.IsInt()) {
275         if (other.IsInt()) {
276             return key.GetInt() == other.GetInt();
277         }
278         return false;
279     }
280 
281     if (key.IsDouble()) {
282         if (other.IsInt()) {
283             int32_t keyValue = static_cast<int32_t>(static_cast<uint32_t>(key.GetDouble()));
284             return keyValue == other.GetInt();
285         }
286         if (other.IsDouble()) {
287             return key.GetDouble() == other.GetDouble();
288         }
289         return false;
290     }
291     // key must be integer
292     LOG_ECMA(FATAL) << "this branch is unreachable";
293     UNREACHABLE();
294 }
295 
GetAllKeys(const JSThread * thread,const JSHandle<NumberDictionary> & obj,int offset,const JSHandle<TaggedArray> & keyArray)296 void NumberDictionary::GetAllKeys(const JSThread *thread, const JSHandle<NumberDictionary> &obj, int offset,
297                                   const JSHandle<TaggedArray> &keyArray)
298 {
299     ASSERT_PRINT(offset + obj->EntriesCount() <= static_cast<int>(keyArray->GetLength()),
300                  "keyArray capacity is not enough for dictionary");
301     int arrayIndex = 0;
302     int size = obj->Size();
303     CVector<JSTaggedValue> sortArr;
304     for (int hashIndex = 0; hashIndex < size; hashIndex++) {
305         JSTaggedValue key = obj->GetKey(thread, hashIndex);
306         if (!key.IsUndefined() && !key.IsHole()) {
307             sortArr.push_back(JSTaggedValue(static_cast<uint32_t>(key.GetInt())));
308         }
309     }
310     std::sort(sortArr.begin(), sortArr.end(), CompKey);
311     for (auto entry : sortArr) {
312         JSHandle<JSTaggedValue> keyHandle(thread, entry);
313         JSHandle<EcmaString> str = JSTaggedValue::ToString(const_cast<JSThread *>(thread), keyHandle);
314         ASSERT_NO_ABRUPT_COMPLETION(thread);
315         keyArray->Set(thread, arrayIndex + offset, str.GetTaggedValue());
316         arrayIndex++;
317     }
318 }
319 
GetAllKeysByFilter(const JSThread * thread,const JSHandle<NumberDictionary> & obj,uint32_t & keyArrayEffectivelength,const JSHandle<TaggedArray> & keyArray,uint32_t filter)320 void NumberDictionary::GetAllKeysByFilter(const JSThread *thread, const JSHandle<NumberDictionary> &obj,
321                                           uint32_t &keyArrayEffectivelength, const JSHandle<TaggedArray> &keyArray,
322                                           uint32_t filter)
323 {
324     ASSERT_PRINT(keyArrayEffectivelength + static_cast<uint32_t>(obj->EntriesCount()) <= keyArray->GetLength(),
325                  "keyArray capacity is not enough for dictionary");
326 
327     CVector<JSTaggedValue> sortArr;
328     uint32_t size = static_cast<uint32_t>(obj->Size());
329     for (uint32_t hashIndex = 0; hashIndex < size; hashIndex++) {
330         JSTaggedValue key = obj->GetKey(thread, hashIndex);
331         if (key.IsUndefined() || key.IsHole()) {
332             continue;
333         }
334 
335         PropertyAttributes attr = obj->GetAttributes(thread, hashIndex);
336         bool bIgnore = FilterHelper::IgnoreKeyByFilter<PropertyAttributes>(attr, filter);
337         if (!bIgnore) {
338             sortArr.push_back(JSTaggedValue(static_cast<uint32_t>(key.GetInt())));
339         }
340     }
341     std::sort(sortArr.begin(), sortArr.end(), CompKey);
342     ASSERT_NO_ABRUPT_COMPLETION(thread);
343     for (auto entry : sortArr) {
344         keyArray->Set(thread, keyArrayEffectivelength, entry);
345         keyArrayEffectivelength++;
346     }
347 }
348 
GetAllEnumKeys(JSThread * thread,const JSHandle<NumberDictionary> & obj,int offset,const JSHandle<TaggedArray> & keyArray,uint32_t * keys,int32_t lastLength)349 void NumberDictionary::GetAllEnumKeys(JSThread *thread, const JSHandle<NumberDictionary> &obj, int offset,
350                                       const JSHandle<TaggedArray> &keyArray, uint32_t *keys, int32_t lastLength)
351 {
352     ASSERT_PRINT(offset + obj->EntriesCount() <= static_cast<int>(keyArray->GetLength()),
353                  "keyArray capacity is not enough for dictionary");
354     uint32_t arrayIndex = 0;
355     int size = obj->Size();
356     CVector<JSTaggedValue> sortArr;
357     for (int hashIndex = 0; hashIndex < size; hashIndex++) {
358         JSTaggedValue key = obj->GetKey(thread, hashIndex);
359         if (!key.IsUndefined() && !key.IsHole()) {
360             PropertyAttributes attr = obj->GetAttributes(thread, hashIndex);
361             if (attr.IsEnumerable()) {
362                 sortArr.push_back(JSTaggedValue(static_cast<uint32_t>(key.GetInt())));
363             }
364         }
365     }
366     std::sort(sortArr.begin(), sortArr.end(), CompKey);
367     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
368     JSHandle<TaggedQueue> emptyQueue = factory->GetEmptyTaggedQueue();
369     JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
370     for (auto entry : sortArr) {
371         keyHandle.Update(entry);
372         JSHandle<EcmaString> str = JSTaggedValue::ToString(const_cast<JSThread *>(thread), keyHandle);
373         ASSERT_NO_ABRUPT_COMPLETION(thread);
374         bool isDuplicated = JSObject::IsDepulicateKeys(thread, keyArray, lastLength, emptyQueue,
375                                                        JSHandle<JSTaggedValue>(str));
376         if (isDuplicated) {
377             continue;
378         }
379         keyArray->Set(thread, arrayIndex + static_cast<uint32_t>(offset), str.GetTaggedValue());
380         arrayIndex++;
381     }
382     *keys += arrayIndex;
383 }
384 
Create(const JSThread * thread,int numberOfElements)385 JSHandle<NumberDictionary> NumberDictionary::Create(const JSThread *thread, int numberOfElements)
386 {
387     return OrderHashTableT::Create(thread, numberOfElements);
388 }
389 
CreateInSharedHeap(const JSThread * thread,int numberOfElements)390 JSHandle<NumberDictionary> NumberDictionary::CreateInSharedHeap(const JSThread *thread, int numberOfElements)
391 {
392     return OrderHashTableT::Create(thread, numberOfElements, MemSpaceKind::SHARED);
393 }
394 
GetAttributes(const JSThread * thread,int entry) const395 PropertyAttributes NumberDictionary::GetAttributes(const JSThread *thread, int entry) const
396 {
397     int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
398     return PropertyAttributes(Get(thread, index));
399 }
400 
SetAttributes(const JSThread * thread,int entry,const PropertyAttributes & metaData)401 void NumberDictionary::SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData)
402 {
403     int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
404     Set(thread, index, metaData.GetTaggedValue());
405 }
406 
SetEntry(const JSThread * thread,int entry,const JSTaggedValue & key,const JSTaggedValue & value,const PropertyAttributes & metaData)407 void NumberDictionary::SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value,
408                                 const PropertyAttributes &metaData)
409 {
410     SetKey(thread, entry, key);
411     SetValue(thread, entry, value);
412     SetAttributes(thread, entry, metaData);
413 }
414 
UpdateValueAndAttributes(const JSThread * thread,int entry,const JSTaggedValue & value,const PropertyAttributes & metaData)415 void NumberDictionary::UpdateValueAndAttributes(const JSThread *thread, int entry, const JSTaggedValue &value,
416                                                 const PropertyAttributes &metaData)
417 {
418     SetValue(thread, entry, value);
419     SetAttributes(thread, entry, metaData);
420 }
421 
UpdateValue(const JSThread * thread,int entry,const JSTaggedValue & value)422 void NumberDictionary::UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value)
423 {
424     SetValue(thread, entry, value);
425 }
426 
ClearEntry(const JSThread * thread,int entry)427 void NumberDictionary::ClearEntry(const JSThread *thread, int entry)
428 {
429     JSTaggedValue hole = JSTaggedValue::Hole();
430     PropertyAttributes metaData;
431     SetEntry(thread, entry, hole, hole, metaData);
432 }
433 
Create(const JSThread * thread,int numberOfElements)434 JSHandle<PointerToIndexDictionary> PointerToIndexDictionary::Create(const JSThread *thread, int numberOfElements)
435 {
436     return OrderHashTableT::Create(thread, numberOfElements);
437 }
438 
PutIfAbsent(const JSThread * thread,const JSHandle<PointerToIndexDictionary> & dictionary,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)439 JSHandle<PointerToIndexDictionary> PointerToIndexDictionary::PutIfAbsent(
440     const JSThread *thread,
441     const JSHandle<PointerToIndexDictionary> &dictionary,
442     const JSHandle<JSTaggedValue> &key,
443     const JSHandle<JSTaggedValue> &value)
444 {
445     /* no need to add key if exist */
446     int entry = dictionary->FindEntry(thread, key.GetTaggedValue());
447     if (entry != -1) {
448         return dictionary;
449     }
450     // Check whether the table should be growed
451     JSHandle<PointerToIndexDictionary> newDictionary = HashTableT::GrowHashTable(thread, dictionary);
452 
453     // Compute the key object
454     uint32_t hash = static_cast<uint32_t>(PointerToIndexDictionary::Hash(thread, key.GetTaggedValue()));
455     entry = newDictionary->FindInsertIndex(thread, hash);
456     newDictionary->SetEntry(thread, entry, key.GetTaggedValue(), value.GetTaggedValue());
457     newDictionary->IncreaseEntries(thread);
458     return newDictionary;
459 }
460 
461 using ProtoArray = FunctionProtoTransitionTable::ProtoArray;
FunctionProtoTransitionTable(const JSThread * thread)462 FunctionProtoTransitionTable::FunctionProtoTransitionTable(const JSThread *thread)
463 {
464     protoTransitionTable_ = PointerToIndexDictionary::Create(thread, DEFAULT_FIRST_LEVEL_SIZE).GetTaggedValue();
465 }
466 
~FunctionProtoTransitionTable()467 FunctionProtoTransitionTable::~FunctionProtoTransitionTable()
468 {
469     fakeParentMap_.clear();
470 }
471 
Iterate(RootVisitor & v)472 void FunctionProtoTransitionTable::Iterate(RootVisitor &v)
473 {
474     v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&protoTransitionTable_)));
475     for (auto &iter : fakeParentMap_) {
476         v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.first)));
477         v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.second)));
478     }
479     for (auto &iter : fakeChildMap_) {
480         v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.first)));
481         v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.second)));
482     }
483 }
484 
UpdateProtoTransitionTable(const JSThread * thread,JSHandle<PointerToIndexDictionary> map)485 void FunctionProtoTransitionTable::UpdateProtoTransitionTable(const JSThread *thread,
486                                                               JSHandle<PointerToIndexDictionary> map)
487 {
488     // PointerToIndexDictionary's hash value is a hclass pointer,
489     // and the hclass pointer could change during deserialized,
490     // so rehash is needed after deserialized.
491     auto newMap = PointerToIndexDictionary::Create(thread, map->Size());
492     map->Rehash(thread, *newMap);
493     protoTransitionTable_ = newMap.GetTaggedValue();
494 }
495 
InsertTransitionItem(const JSThread * thread,JSHandle<JSTaggedValue> ihc,JSHandle<JSTaggedValue> baseIhc,JSHandle<JSTaggedValue> transIhc,JSHandle<JSTaggedValue> transPhc)496 void FunctionProtoTransitionTable::InsertTransitionItem(const JSThread *thread,
497                                                         JSHandle<JSTaggedValue> ihc,
498                                                         JSHandle<JSTaggedValue> baseIhc,
499                                                         JSHandle<JSTaggedValue> transIhc,
500                                                         JSHandle<JSTaggedValue> transPhc)
501 {
502     JSHandle<PointerToIndexDictionary> protoTransitionHandle(thread, protoTransitionTable_);
503     int32_t entry1 = protoTransitionHandle->FindEntry(thread, ihc.GetTaggedValue());
504     if (entry1 != -1) {
505         JSHandle<ProtoArray> protoArray(thread, protoTransitionHandle->GetValue(thread, entry1));
506         auto entry2 = protoArray->FindEntry(thread, baseIhc.GetTaggedValue());
507         if (entry2 != -1) {
508             LOG_ECMA(DEBUG) << "Record prototype for current function already!";
509             return;
510         }
511         uint32_t insertEntry = ProtoArray::GetEntry(JSHandle<JSHClass>(baseIhc));
512         protoArray->SetEntry(
513             thread, insertEntry, baseIhc.GetTaggedValue(), transIhc.GetTaggedValue(), transPhc.GetTaggedValue());
514         return;
515     }
516     JSHandle<ProtoArray> protoArray = ProtoArray::Create(thread);
517     uint32_t insertEntry = ProtoArray::GetEntry(JSHandle<JSHClass>(baseIhc));
518     protoArray->SetEntry(
519         thread, insertEntry, baseIhc.GetTaggedValue(), transIhc.GetTaggedValue(), transPhc.GetTaggedValue());
520     JSHandle<PointerToIndexDictionary> newTransitionTable =
521         PointerToIndexDictionary::PutIfAbsent(thread, protoTransitionHandle, ihc, JSHandle<JSTaggedValue>(protoArray));
522     protoTransitionTable_ = newTransitionTable.GetTaggedValue();
523 }
524 
FindTransitionByHClass(const JSThread * thread,JSHandle<JSTaggedValue> ihc,JSHandle<JSTaggedValue> baseIhc) const525 std::pair<JSTaggedValue, JSTaggedValue> FunctionProtoTransitionTable::FindTransitionByHClass(
526     const JSThread *thread, JSHandle<JSTaggedValue> ihc, JSHandle<JSTaggedValue> baseIhc) const
527 {
528     ASSERT(ihc->IsJSHClass());
529     ASSERT(baseIhc->IsJSHClass());
530     JSHandle<PointerToIndexDictionary> protoTransitionHandle(thread, protoTransitionTable_);
531     int32_t entry1 = protoTransitionHandle->FindEntry(thread, ihc.GetTaggedValue());
532     if (entry1 == -1) {
533         LOG_ECMA(DEBUG) << "Selected ihc not found2!";
534         return std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined());
535     }
536     JSHandle<ProtoArray> protoArray(thread, protoTransitionHandle->GetValue(thread, entry1));
537     int32_t entry2 = protoArray->FindEntry(thread, baseIhc.GetTaggedValue());
538     if (entry2 == -1) {
539         LOG_ECMA(ERROR) << "Selected baseIhc not found!";
540         return std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined());
541     }
542     return protoArray->GetTransition(thread, entry2);
543 }
544 
TryInsertFakeParentItem(JSTaggedType child,JSTaggedType parent)545 bool FunctionProtoTransitionTable::TryInsertFakeParentItem(JSTaggedType child, JSTaggedType parent)
546 {
547     LockHolder lock(fakeParentMutex_);
548     // Situation:
549     // 1: d1.prototype = p
550     // 2: d2.prototype = p
551     // this check is true for step 2
552     auto iter1 = fakeParentMap_.find(child);
553     if (child == parent && iter1 != fakeParentMap_.end()) {
554         return true;
555     }
556     auto iter2 = fakeChildMap_.find(parent);
557     if (iter2 != fakeChildMap_.end()) {
558         if (iter2->second != child) {
559             LOG_ECMA(DEBUG) << "Unsupported mapping for a parent to more than 1 childs!";
560             return false;
561         }
562     }
563 
564     if (iter1 == fakeParentMap_.end()) {
565         fakeParentMap_[child] = parent;
566         fakeChildMap_[parent] = child;
567         return true;
568     }
569     if (iter1->second == parent) {
570         return true;
571     }
572     LOG_ECMA(ERROR) << "Conflict mapping for the same child";
573     return false;
574 }
575 
GetFakeParent(JSTaggedType child)576 JSTaggedType FunctionProtoTransitionTable::GetFakeParent(JSTaggedType child)
577 {
578     LockHolder lock(fakeParentMutex_);
579     auto iter = fakeParentMap_.find(child);
580     if (iter != fakeParentMap_.end()) {
581         return iter->second;
582     }
583     return 0;
584 }
585 
586 // static
Create(const JSThread * thread)587 JSHandle<ProtoArray> ProtoArray::Create(const JSThread *thread)
588 {
589     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
590     JSHandle<TaggedArray> result = factory->NewTaggedArray(ENTRY_NUMBER * ENTRY_SIZE);
591     return JSHandle<ProtoArray>(result);
592 }
593 
594 // static
GetEntry(JSHandle<JSHClass> hclass)595 bool ProtoArray::GetEntry(JSHandle<JSHClass> hclass)
596 {
597     return JSHandle<JSHClass>(hclass)->IsPrototype() ? ProtoArray::CLONED_ENTRY_INDEX
598                                                      : ProtoArray::INIT_ENTRY_INDEX;
599 }
600 
SetEntry(const JSThread * thread,uint32_t index,JSTaggedValue key,JSTaggedValue transIhc,JSTaggedValue transPhc)601 void ProtoArray::SetEntry(const JSThread *thread, uint32_t index, JSTaggedValue key, JSTaggedValue transIhc,
602                           JSTaggedValue transPhc)
603 {
604     uint32_t entryIndex = index * ENTRY_SIZE;
605     uint32_t keyIndex = entryIndex + KEY_INDEX;
606     uint32_t ihcIndex = entryIndex + TRANS_IHC_INDEX;
607     uint32_t phcIndex = entryIndex + TRANS_PHC_INDEX;
608     Set(thread, keyIndex, key);
609     Set(thread, ihcIndex, transIhc);
610     Set(thread, phcIndex, transPhc);
611 }
612 
GetKey(const JSThread * thread,uint32_t index) const613 JSTaggedValue ProtoArray::GetKey(const JSThread *thread, uint32_t index) const
614 {
615     uint32_t entryIndex = index * ENTRY_SIZE;
616     uint32_t keyIndex = entryIndex + KEY_INDEX;
617     return Get(thread, keyIndex);
618 }
619 
GetTransition(const JSThread * thread,uint32_t index) const620 std::pair<JSTaggedValue, JSTaggedValue> ProtoArray::GetTransition(const JSThread *thread, uint32_t index) const
621 {
622     uint32_t entryIndex = index * ENTRY_SIZE + KEY_INDEX;
623     JSTaggedValue transIhc = Get(thread, entryIndex + TRANS_IHC_INDEX);
624     JSTaggedValue transPhc = Get(thread, entryIndex + TRANS_PHC_INDEX);
625     return std::make_pair(transIhc, transPhc);
626 }
627 
FindTransition(const JSThread * thread,JSTaggedValue key) const628 std::pair<JSTaggedValue, JSTaggedValue> ProtoArray::FindTransition(const JSThread *thread, JSTaggedValue key) const
629 {
630     for (uint32_t i = 0; i < ENTRY_NUMBER; i++) {
631         uint32_t index = i * ENTRY_SIZE + KEY_INDEX;
632         JSTaggedValue keyValue = Get(thread, index);
633         if (keyValue == key) {
634             JSTaggedValue transIhc = Get(thread, index + TRANS_IHC_INDEX);
635             JSTaggedValue transPhc = Get(thread, index + TRANS_PHC_INDEX);
636             return std::make_pair(transIhc, transPhc);
637         }
638     }
639     return std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined());
640 }
641 
FindEntry(const JSThread * thread,JSTaggedValue key) const642 int32_t ProtoArray::FindEntry(const JSThread *thread, JSTaggedValue key) const
643 {
644     for (uint32_t i = 0; i < ENTRY_NUMBER; i++) {
645         uint32_t index = i * ENTRY_SIZE + KEY_INDEX;
646         JSTaggedValue keyValue = Get(thread, index);
647         if (keyValue == key) {
648             return i;
649         }
650     }
651     return -1;
652 }
653 }  // namespace panda::ecmascript
654