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