• 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_IC_MEGA_IC_CACHE_H
17 #define ECMASCRIPT_IC_MEGA_IC_CACHE_H
18 
19 #include <array>
20 
21 #include "ecmascript/js_hclass.h"
22 #include "ecmascript/js_tagged_value.h"
23 #include "ecmascript/ecma_macros.h"
24 #include "ecmascript/log_wrapper.h"
25 #include "ecmascript/log_wrapper.h"
26 #include "jsnapi_expo.h"
27 
28 namespace panda::ecmascript {
29 class EcmaVM;
30 class MegaICCache {
31 public:
32     enum MegaICKind {
33         None,
34         Load,
35         Store,
36     };
Get(const JSThread * thread,JSHClass * jsHclass,JSTaggedValue key)37     JSTaggedValue Get(const JSThread *thread, JSHClass *jsHclass, JSTaggedValue key)
38     {
39         int hash = PrimaryHash(thread, jsHclass, key);
40         PropertyKey &prop = primary_[hash];
41         if ((prop.hclass_ == jsHclass) && (prop.key_ == key)) {
42             return primary_[hash].results_;
43         }
44         int secondaryHash = SecondaryHash(jsHclass, key);
45         PropertyKey &secondaryProp = secondary_[secondaryHash];
46         if ((secondaryProp.hclass_ == jsHclass) && (secondaryProp.key_ == key)) {
47             return secondary_[secondaryHash].results_;
48         }
49         return NOT_FOUND;
50     }
51     void Set(JSHClass *jsHclass, JSTaggedValue key, JSTaggedValue handler, JSThread* thread);
Clear()52     inline void Clear()
53     {
54         for (auto &key : primary_) {
55             key.hclass_ = nullptr;
56             key.key_ = JSTaggedValue::Hole();
57         }
58         for (auto &key : secondary_) {
59             key.hclass_ = nullptr;
60             key.key_ = JSTaggedValue::Hole();
61         }
62     }
IsCleared()63     bool IsCleared() const
64     {
65         for (auto &key : primary_) {
66             if (key.hclass_ != nullptr) {
67                 return false;
68             }
69         }
70         for (auto &key : secondary_) {
71             if (key.hclass_ != nullptr) {
72                 return false;
73             }
74         }
75         return true;
76     }
77 
PrintLoadFactor()78     bool PrintLoadFactor() const
79     {
80         int tot = 0;
81         for (auto &key : primary_) {
82             if (key.hclass_ != nullptr) {
83                 tot++;
84             }
85         }
86         LOG_JIT(INFO) << "PrimaryTable LoadFactor:" << (double)tot / PRIMARY_LENGTH;
87         tot = 0;
88         for (auto &key : secondary_) {
89             if (key.hclass_ != nullptr) {
90                 tot++;
91             }
92         }
93         LOG_JIT(INFO) << "SecondaryTable LoadFactor:" << (double)tot / SECONDARY_LENGTH;
94 
95         return true;
96     }
97 
Iterate(RootVisitor & v)98     void Iterate(RootVisitor &v)
99     {
100         for (auto &key : primary_) {
101             if (key.hclass_ != nullptr) {
102                 auto value = JSTaggedValue::Cast(key.hclass_);
103                 v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(value))));
104             }
105             v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(key.key_))));
106             v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(key.results_))));
107         }
108         for (auto &key : secondary_) {
109             if (key.hclass_ != nullptr) {
110                 auto value = JSTaggedValue::Cast(key.hclass_);
111                 v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(value))));
112             }
113             v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(key.key_))));
114             v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(key.results_))));
115         }
116     }
117 
GetSecondaryOffset()118     static size_t GetSecondaryOffset()
119     {
120         return sizeof(PropertyKey) * PRIMARY_LENGTH;
121     }
122 
123     constexpr static const JSTaggedValue NOT_FOUND = JSTaggedValue::Hole();
124     static const uint32_t PRIMARY_LENGTH_BIT = 10;
125     static const uint32_t PRIMARY_LENGTH = (1U << PRIMARY_LENGTH_BIT);
126     static const uint32_t PRIMARY_LENGTH_MASK = PRIMARY_LENGTH - 1;
127     static const uint32_t SECONDARY_LENGTH_BIT = 9;
128     static const uint32_t SECONDARY_LENGTH = (1U << SECONDARY_LENGTH_BIT);
129     static const uint32_t SECONDARY_LENGTH_MASK = SECONDARY_LENGTH - 1;
130     static const uint32_t HCLASS_SHIFT = 3;
131     struct PropertyKey : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
132                                                     base::AlignedPointer,
133                                                     JSTaggedValue,
134                                                     JSTaggedValue> {
135         enum class Index : size_t {
136             HclassIndex = 0,
137             KeyIndex,
138             ResultsIndex,
139             NumOfMembers
140         };
141         static size_t GetHclassOffset(bool isArch32 = false)
142         {
143             return GetOffset<static_cast<size_t>(Index::HclassIndex)>(isArch32);
144         }
145 
146         static size_t GetKeyOffset(bool isArch32 = false)
147         {
148             return GetOffset<static_cast<size_t>(Index::KeyIndex)>(isArch32);
149         }
150 
151         static size_t GetResultsOffset(bool isArch32 = false)
152         {
153             return GetOffset<static_cast<size_t>(Index::ResultsIndex)>(isArch32);
154         }
155 
GetPropertyKeySizePropertyKey156         static size_t GetPropertyKeySize()
157         {
158             return static_cast<size_t>(Index::NumOfMembers) * static_cast<size_t>(JSTaggedValue::TaggedTypeSize());
159         }
160 
161         static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
162         alignas(EAS) JSHClass *hclass_ {nullptr};
163         alignas(EAS) JSTaggedValue key_ {JSTaggedValue::Hole()};
164         alignas(EAS) JSTaggedValue results_ {JSTaggedValue::Hole()};
165     };
166 
167 private:
MegaICCache()168     MegaICCache()
169     {
170         for (uint32_t i = 0; i < PRIMARY_LENGTH; ++i) {
171             primary_[i].hclass_ = nullptr;
172             primary_[i].key_ = JSTaggedValue::Hole();
173             primary_[i].results_ = NOT_FOUND;
174         }
175         for (uint32_t i = 0; i < SECONDARY_LENGTH; ++i) {
176             secondary_[i].hclass_ = nullptr;
177             secondary_[i].key_ = JSTaggedValue::Hole();
178             secondary_[i].results_ = NOT_FOUND;
179         }
180     }
181     ~MegaICCache() = default;
182 
183     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
PrimaryHash(const JSThread * thread,JSHClass * cls,JSTaggedValue key)184     static inline int PrimaryHash(const JSThread *thread, JSHClass *cls, JSTaggedValue key)
185     {
186         uint32_t clsHash = static_cast<uint32_t>(
187             reinterpret_cast<uintptr_t>(cls) ^
188             (reinterpret_cast<uintptr_t>(cls) >> PRIMARY_LENGTH_BIT));
189         uint32_t keyHash = key.GetStringKeyHashCode(thread);
190         uint32_t hash = clsHash + keyHash;
191         return static_cast<int>((hash) & PRIMARY_LENGTH_MASK);
192     }
193 
SecondaryHash(JSHClass * cls,JSTaggedValue key)194     static inline int SecondaryHash(JSHClass *cls, JSTaggedValue key)
195     {
196         uint32_t clsHash = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(cls)) >> HCLASS_SHIFT;  // skip 8bytes
197         uint32_t keyHash = static_cast<uint32_t>(key.GetRawData());
198         uint32_t hash = clsHash + keyHash;
199         hash = hash + (hash >> SECONDARY_LENGTH_BIT);
200         return static_cast<int>((hash) & SECONDARY_LENGTH_MASK);
201     }
202 
203     PropertyKey primary_[PRIMARY_LENGTH];
204     PropertyKey secondary_[SECONDARY_LENGTH];
205 
206     friend class JSThread;
207 };
208 }  // namespace panda::ecmascript
209 #endif  // ECMASCRIPT_IC_MEGA_IC_CACHE_H
210