1 /* 2 * Copyright (c) 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 #ifndef ECMASCRIPT_REQUIRE_JS_CJS_MODULE_CACHE_H 17 #define ECMASCRIPT_REQUIRE_JS_CJS_MODULE_CACHE_H 18 19 #include "ecmascript/ecma_vm.h" 20 #include "ecmascript/object_factory.h" 21 #include "ecmascript/tagged_hash_table.h" 22 #include "ecmascript/ecma_string.h" 23 #include "ecmascript/require/js_cjs_module.h" 24 #include "ecmascript/js_thread.h" 25 26 namespace panda::ecmascript { 27 class CjsModuleCache : public TaggedHashTable<CjsModuleCache> { 28 public: 29 using HashTable = TaggedHashTable<CjsModuleCache>; 30 Cast(TaggedObject * object)31 static CjsModuleCache *Cast(TaggedObject *object) 32 { 33 ASSERT(JSTaggedValue(object).IsTaggedArray()); 34 return reinterpret_cast<CjsModuleCache *>(object); 35 } 36 GetKeyIndex(int entry)37 inline static int GetKeyIndex(int entry) 38 { 39 return HashTable::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_KEY_INDEX; 40 } 41 GetValueIndex(int entry)42 inline static int GetValueIndex(int entry) 43 { 44 return HashTable::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_VALUE_INDEX; 45 } 46 GetEntryIndex(int entry)47 inline static int GetEntryIndex(int entry) 48 { 49 return HashTable::TABLE_HEADER_SIZE + entry * GetEntrySize(); 50 } 51 GetEntrySize()52 inline static int GetEntrySize() 53 { 54 return ENTRY_SIZE; 55 } 56 IsMatch(const JSTaggedValue & fileName,const JSTaggedValue & other)57 static inline bool IsMatch(const JSTaggedValue &fileName, const JSTaggedValue &other) 58 { 59 if (fileName.IsHole() || fileName.IsUndefined()) { 60 return false; 61 } 62 63 auto *nameString = static_cast<EcmaString *>(fileName.GetTaggedObject()); 64 auto *otherString = static_cast<EcmaString *>(other.GetTaggedObject()); 65 return EcmaStringAccessor::StringsAreEqual(nameString, otherString); 66 } 67 Hash(const JSTaggedValue & key)68 static inline int Hash(const JSTaggedValue &key) 69 { 70 ASSERT(key.IsString()); 71 EcmaString *nameStr = static_cast<EcmaString *>(key.GetTaggedObject()); 72 return static_cast<int>(EcmaStringAccessor(nameStr).GetHashcode()); 73 } 74 75 static const int DEFAULT_ELEMENTS_NUMBER = 64; 76 77 static JSHandle<CjsModuleCache> Create(JSThread *thread, int numberOfElements = DEFAULT_ELEMENTS_NUMBER) 78 { 79 return HashTable::Create(thread, numberOfElements); 80 } 81 FindEntry(const JSTaggedValue & key)82 inline int FindEntry(const JSTaggedValue &key) 83 { 84 int size = Size(); 85 int count = 1; 86 JSTaggedValue keyValue; 87 uint32_t hash = Hash(key); 88 89 for (uint32_t entry = GetFirstPosition(hash, size);; entry = GetNextPosition(entry, count++, size)) { 90 keyValue = GetKey(entry); 91 if (keyValue.IsHole()) { 92 continue; 93 } 94 if (keyValue.IsUndefined()) { 95 return -1; 96 } 97 if (IsMatch(key, keyValue)) { 98 return entry; 99 } 100 } 101 return -1; 102 } 103 ContainsModule(const JSTaggedValue & key)104 inline bool ContainsModule(const JSTaggedValue &key) 105 { 106 int entry = FindEntry(key); 107 return entry != -1; 108 } 109 GetModule(const JSTaggedValue & key)110 inline JSTaggedValue GetModule(const JSTaggedValue &key) 111 { 112 int entry = FindEntry(key); 113 ASSERT(entry != -1); 114 return GetValue(entry); 115 } 116 SetEntry(const JSThread * thread,int entry,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)117 inline void SetEntry(const JSThread *thread, int entry, 118 const JSHandle<JSTaggedValue> &key, 119 const JSHandle<JSTaggedValue> &value) 120 { 121 JSTaggedValue keyValue = key.GetTaggedValue(); 122 JSTaggedValue valueValue = value.GetTaggedValue(); 123 SetKey(thread, entry, keyValue); 124 SetValue(thread, entry, valueValue); 125 } 126 127 static JSHandle<CjsModuleCache> PutIfAbsentAndReset(const JSThread *thread, 128 const JSHandle<CjsModuleCache> &dictionary, 129 const JSHandle<JSTaggedValue> &key, 130 const JSHandle<JSTaggedValue> &value); 131 static JSHandle<CjsModuleCache> ResetModule(const JSThread *thread, 132 const JSHandle<CjsModuleCache> &dictionary, 133 const JSHandle<JSTaggedValue> &key, 134 const JSHandle<JSTaggedValue> &value); ComputeCompactSize(const JSHandle<CjsModuleCache> & table,int computeHashTableSize,int tableSize,int addedElements)135 static int ComputeCompactSize([[maybe_unused]] const JSHandle<CjsModuleCache> &table, int computeHashTableSize, 136 [[maybe_unused]] int tableSize, [[maybe_unused]] int addedElements) 137 { 138 return computeHashTableSize; 139 } 140 static constexpr int ENTRY_KEY_INDEX = 0; 141 static constexpr int ENTRY_VALUE_INDEX = 1; 142 static constexpr int ENTRY_SIZE = 2; 143 static constexpr int DEAULT_DICTIONART_CAPACITY = 4; 144 }; 145 } // namespace panda::ecmascript 146 #endif // ECMASCRIPT_REQUIRE_JS_CJS_MODULE_CACHE_H