• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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_IC_HANDLER_H
17 #define ECMASCRIPT_IC_IC_HANDLER_H
18 
19 #include "ecmascript/ecma_macros.h"
20 #include "ecmascript/js_tagged_value-inl.h"
21 #include "ecmascript/js_typed_array.h"
22 #include "ecmascript/mem/tagged_object.h"
23 #include "ecmascript/object_operator.h"
24 #include "ecmascript/js_function.h"
25 
26 namespace panda::ecmascript {
27 class HandlerBase {
28 public:
29     static constexpr uint32_t KIND_BIT_LENGTH = 4;
30     static constexpr uint32_t STORE_KIND_BIT_LENGTH = 2;
31     static constexpr uint32_t MAX_BIT_SIZE = 48;
32     enum HandlerKind {
33         NONE = 0,
34         FIELD,
35         ELEMENT,
36         DICTIONARY,
37         STRING,
38         STRING_LENGTH,
39         TYPED_ARRAY,
40         NUMBER,
41         NON_EXIST,
42         TOTAL_KINDS,
43     };
44     static_assert(static_cast<size_t>(HandlerKind::TOTAL_KINDS) <= (1 << KIND_BIT_LENGTH));
45 
46     // Store Handler kind combined with KindBit called SWholeKindBit. Which used to quickly check S_FIELD kind
47     enum StoreHandlerKind {
48         S_NONE = HandlerKind::NONE,
49         S_FIELD,
50         S_ELEMENT,
51         S_TOTAL_KINDS,
52     };
53     static_assert(static_cast<size_t>(StoreHandlerKind::S_TOTAL_KINDS) <= (1 << STORE_KIND_BIT_LENGTH));
54 
55     // For Load
56     using KindBit = BitField<HandlerKind, 0, KIND_BIT_LENGTH>;                                              // [0, 4)
57     using InlinedPropsBit = KindBit::NextFlag;                                                              // [4, 5)
58     using AccessorBit = InlinedPropsBit::NextFlag;                                                          // [5, 6)
59     using IsJSArrayBit = AccessorBit::NextFlag;                                                             // [6, 7)
60     using OffsetBit = IsJSArrayBit::NextField<uint32_t, PropertyAttributes::MAX_FAST_PROPS_CAPACITY_LOG2>;  // [7, 17)
61     using RepresentationBit = OffsetBit::NextField<Representation, PropertyAttributes::REPRESENTATION_NUM>; // [17, 19)
62     using AttrIndexBit =
63         RepresentationBit::NextField<uint32_t, PropertyAttributes::MAX_FAST_PROPS_CAPACITY_LOG2>;           // [19, 29)
64     using IsOnHeapBit = AttrIndexBit::NextFlag;                                                             // [29, 30)
65     using NeedSkipInPGODumpBit  = IsOnHeapBit::NextFlag;                                                    // [30, 31)
66     static_assert(NeedSkipInPGODumpBit::END_BIT <= MAX_BIT_SIZE, "load handler overflow");
67 
68     // For Store
69     using SWholeKindBit = KindBit;
70     using SKindBit = BitField<StoreHandlerKind, 0, STORE_KIND_BIT_LENGTH>;                                  // [0, 2)
71     static_assert(SKindBit::START_BIT == KindBit::START_BIT);
72     using SSharedBit = SKindBit::NextFlag;                                                                  // [2, 4)
73     static_assert((SKindBit::SIZE + SSharedBit::SIZE) <= KindBit::SIZE);              // reuse: [0, 4) bits
74                                                                                       // shared with Load bits: [4, 30)
75     using SOutOfBoundsBit = IsOnHeapBit::NextFlag;                                    // reuse: [30, 31) bit
76     using SFieldTypeBit = SOutOfBoundsBit::NextField<SharedFieldType, PropertyAttributes::FIELD_TYPE_NUM>;  // [31, 39)
77     static_assert(SFieldTypeBit::END_BIT <= MAX_BIT_SIZE, "store handler overflow");
78     using Type = uint64_t;
79     static_assert(sizeof(Type) <= JSTaggedValue::TaggedTypeSize());
80 
81     HandlerBase() = default;
82     virtual ~HandlerBase() = default;
83 
IsAccessor(Type handler)84     static inline bool IsAccessor(Type handler)
85     {
86         return AccessorBit::Get(handler);
87     }
88 
GetFieldType(Type handler)89     static inline SharedFieldType GetFieldType(Type handler)
90     {
91         return static_cast<SharedFieldType>(SFieldTypeBit::Get(handler));
92     }
93 
IsNonExist(Type handler)94     static inline bool IsNonExist(Type handler)
95     {
96         return GetKind(handler) == HandlerKind::NON_EXIST;
97     }
98 
IsField(Type handler)99     static inline bool IsField(Type handler)
100     {
101         return GetKind(handler) == HandlerKind::FIELD;
102     }
103 
IsNonSharedStoreField(Type handler)104     static inline bool IsNonSharedStoreField(Type handler)
105     {
106         return static_cast<StoreHandlerKind>(GetKind(handler)) == StoreHandlerKind::S_FIELD;
107     }
108 
IsStoreShared(Type handler)109     static inline bool IsStoreShared(Type handler)
110     {
111         return SSharedBit::Get(handler);
112     }
113 
ClearSharedStoreKind(Type & handler)114     static inline void ClearSharedStoreKind(Type &handler)
115     {
116         SSharedBit::Set<Type>(false, &handler);
117     }
118 
IsStoreOutOfBounds(Type handler)119     static inline bool IsStoreOutOfBounds(Type handler)
120     {
121         return SOutOfBoundsBit::Get(handler);
122     }
123 
ClearStoreOutOfBounds(Type & handler)124     static inline void ClearStoreOutOfBounds(Type &handler)
125     {
126         SOutOfBoundsBit::Set<Type>(false, &handler);
127     }
128 
IsString(Type handler)129     static inline bool IsString(Type handler)
130     {
131         return GetKind(handler) == HandlerKind::STRING;
132     }
133 
IsNumber(Type handler)134     static inline bool IsNumber(Type handler)
135     {
136         return GetKind(handler) == HandlerKind::NUMBER;
137     }
138 
IsStringLength(Type handler)139     static inline bool IsStringLength(Type handler)
140     {
141         return GetKind(handler) == HandlerKind::STRING_LENGTH;
142     }
143 
IsElement(Type handler)144     static inline bool IsElement(Type handler)
145     {
146         return IsNormalElement(handler) || IsStringElement(handler) || IsTypedArrayElement(handler);
147     }
148 
IsNormalElement(Type handler)149     static inline bool IsNormalElement(Type handler)
150     {
151         return GetKind(handler) == HandlerKind::ELEMENT;
152     }
153 
IsStringElement(Type handler)154     static inline bool IsStringElement(Type handler)
155     {
156         return GetKind(handler) == HandlerKind::STRING;
157     }
158 
IsTypedArrayElement(Type handler)159     static inline bool IsTypedArrayElement(Type handler)
160     {
161         return GetKind(handler) == HandlerKind::TYPED_ARRAY;
162     }
163 
IsDictionary(Type handler)164     static inline bool IsDictionary(Type handler)
165     {
166         return GetKind(handler) == HandlerKind::DICTIONARY;
167     }
168 
IsInlinedProps(Type handler)169     static inline bool IsInlinedProps(Type handler)
170     {
171         return InlinedPropsBit::Get(handler);
172     }
173 
GetKind(Type handler)174     static inline HandlerKind GetKind(Type handler)
175     {
176         return KindBit::Get(handler);
177     }
178 
IsJSArray(Type handler)179     static inline bool IsJSArray(Type handler)
180     {
181         return IsJSArrayBit::Get(handler);
182     }
183 
NeedSkipInPGODump(Type handler)184     static inline bool NeedSkipInPGODump(Type handler)
185     {
186         return NeedSkipInPGODumpBit::Get(handler);
187     }
188 
GetOffset(Type handler)189     static inline int GetOffset(Type handler)
190     {
191         return OffsetBit::Get(handler);
192     }
193 
IsOnHeap(Type handler)194     static inline bool IsOnHeap(Type handler)
195     {
196         return IsOnHeapBit::Get(handler);
197     }
198 
199     static void PrintLoadHandler(uint64_t handler, std::ostream& os);
200     static void PrintStoreHandler(uint64_t handler, std::ostream& os);
201 };
202 
203 class LoadHandler final : public HandlerBase {
204 public:
205     static JSHandle<JSTaggedValue> LoadProperty(const JSThread *thread, const ObjectOperator &op);
206     static JSHandle<JSTaggedValue> LoadElement(const JSThread *thread, const ObjectOperator &op);
207 
LoadStringElement(const JSThread * thread)208     static inline JSHandle<JSTaggedValue> LoadStringElement(const JSThread *thread)
209     {
210         uint64_t handler = 0;
211         KindBit::Set<uint64_t>(HandlerKind::STRING, &handler);
212         return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
213     }
214 
LoadTypedArrayElement(const JSThread * thread,JSHandle<JSTypedArray> typedArray)215     static inline JSHandle<JSTaggedValue> LoadTypedArrayElement(const JSThread *thread,
216                                                                 JSHandle<JSTypedArray> typedArray)
217     {
218         uint64_t handler = 0;
219         KindBit::Set<uint64_t>(HandlerKind::TYPED_ARRAY, &handler);
220         IsOnHeapBit::Set<uint64_t>(JSHandle<TaggedObject>(typedArray)->GetClass()->IsOnHeapFromBitField(), &handler);
221         return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
222     }
223 };
224 
225 class StoreHandler final : public HandlerBase {
226 public:
227     static JSHandle<JSTaggedValue> StoreProperty(const JSThread *thread, const ObjectOperator &op);
228 
StoreElement(const JSThread * thread,JSHandle<JSTaggedValue> receiver,uint64_t handler)229     static inline JSHandle<JSTaggedValue> StoreElement(const JSThread *thread,
230                                                        JSHandle<JSTaggedValue> receiver, uint64_t handler)
231     {
232         SKindBit::Set<uint64_t>(StoreHandlerKind::S_ELEMENT, &handler);
233 
234         if (receiver->IsJSArray()) {
235             IsJSArrayBit::Set<uint64_t>(true, &handler);
236         }
237         return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
238     }
239 
SFieldTypeBitSet(const ObjectOperator & op,JSHandle<JSObject> & receiver,uint64_t * handler)240     static inline void SFieldTypeBitSet(const ObjectOperator &op, JSHandle<JSObject> &receiver, uint64_t *handler)
241     {
242         SSharedBit::Set<uint64_t>(op.GetReceiver()->IsJSShared(), handler);
243         TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
244         if (!array->IsDictionaryMode()) {
245             SFieldTypeBit::Set<uint64_t>(op.GetAttr().GetSharedFieldType(), handler);
246         } else {
247             SFieldTypeBit::Set<uint64_t>(op.GetAttr().GetDictSharedFieldType(), handler);
248         }
249     }
250 };
251 
252 class TransitionHandler : public TaggedObject {
253 public:
Cast(TaggedObject * object)254     static TransitionHandler *Cast(TaggedObject *object)
255     {
256         ASSERT(JSTaggedValue(object).IsTransitionHandler());
257         return static_cast<TransitionHandler *>(object);
258     }
259 
260     static JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op);
261 
262     static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
263     ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET)
264     ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, SIZE)
265 
266     DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE)
267     DECL_DUMP()
268 };
269 
270 class PrototypeHandler : public TaggedObject {
271 public:
Cast(TaggedObject * object)272     static PrototypeHandler *Cast(TaggedObject *object)
273     {
274         ASSERT(JSTaggedValue(object).IsPrototypeHandler());
275         return static_cast<PrototypeHandler *>(object);
276     }
277 
278     static JSHandle<JSTaggedValue> LoadPrototype(const JSThread *thread, const ObjectOperator &op,
279                                                         const JSHandle<JSHClass> &hclass);
280     static JSHandle<JSTaggedValue> StorePrototype(const JSThread *thread, const ObjectOperator &op,
281                                                          const JSHandle<JSHClass> &hclass);
282 
283     static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
284     ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET)
285     ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET)
286     ACCESSORS(Holder, HOLDER_OFFSET, ACCESSOR_JSFUNCTION_OFFSET)
287     ACCESSORS(AccessorJSFunction, ACCESSOR_JSFUNCTION_OFFSET, ACCESSOR_METHOD_ID_OFFSET)
288     ACCESSORS_PRIMITIVE_FIELD(AccessorMethodId, uint32_t, ACCESSOR_METHOD_ID_OFFSET, LAST_OFFSET)
289 
290     DEFINE_ALIGN_SIZE(LAST_OFFSET);
291     DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, ACCESSOR_METHOD_ID_OFFSET)
292     DECL_DUMP()
293 };
294 
295 class TransWithProtoHandler : public TaggedObject {
296 public:
Cast(TaggedObject * object)297     static TransWithProtoHandler *Cast(TaggedObject *object)
298     {
299         ASSERT(JSTaggedValue(object).IsTransWithProtoHandler());
300         return static_cast<TransWithProtoHandler *>(object);
301     }
302 
303     static JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op,
304                                                           const JSHandle<JSHClass> &hclass);
305 
306     static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
307     ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET)
308     ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, PROTO_CELL_OFFSET)
309     ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, SIZE)
310 
311     DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE)
312     DECL_DUMP()
313 };
314 
315 class StoreAOTHandler : public TaggedObject {
316 public:
Cast(TaggedObject * object)317     static StoreAOTHandler *Cast(TaggedObject *object)
318     {
319         ASSERT(JSTaggedValue(object).IsStoreAOTHandler());
320         return static_cast<StoreAOTHandler *>(object);
321     }
322 
323     static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
324     ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET)
325     ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET)
326     ACCESSORS(Holder, HOLDER_OFFSET, SIZE)
327 
328     DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE)
329     DECL_DUMP()
330 };
331 }  // namespace panda::ecmascript
332 #endif  // ECMASCRIPT_IC_IC_HANDLER_H
333