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_PROPERTY_ATTRIBUTES_H
17#define ECMASCRIPT_PROPERTY_ATTRIBUTES_H
18
19#include "ecmascript/js_tagged_value.h"
20
21#include "libpandabase/utils/bit_field.h"
22
23namespace panda::ecmascript {
24class PropertyDescriptor;
25
26enum class Representation {
27    NONE,
28    INT,
29    DOUBLE,
30    TAGGED,
31};
32
33enum class TrackType : uint8_t {
34    NONE = 0x0ULL,
35    INT = 0x1ULL,
36    DOUBLE = 0x1ULL << 1,
37    NUMBER = INT | DOUBLE,
38    TAGGED = 0x1ULL << 2
39};
40enum class SharedFieldType {
41    NONE = 0,
42    NUMBER = (1 << 0),
43    STRING = (1 << 1),
44    BOOLEAN = (1 << 2),
45    SENDABLE = (1 << 3),
46    BIG_INT = (1 << 4),
47    GENERIC = (1 << 5),
48    NULL_TYPE = (1 << 6),
49    UNDEFINED = (1 << 7),
50};
51
52enum class PropertyBoxType {
53    // Meaningful when a property cell does not contain the hole.
54    UNDEFINED,     // The PREMONOMORPHIC of property cells.
55    CONSTANT,      // Cell has been assigned only once.
56    CONSTANTTYPE,  // Cell has been assigned only one type.
57    MUTABLE,       // Cell will no longer be tracked as constant.
58
59    // Meaningful when a property cell contains the hole.
60    UNINITIALIZED = UNDEFINED,  // Cell has never been initialized.
61    INVALIDATED = CONSTANT,     // Cell has been deleted, invalidated or never existed.
62};
63
64/**
65 * [bitfield]
66 *  Common | WritableField (bit 1)
67 *         | EnumerableField (bit 2)
68 *         | ConfigurableField (bit 3)
69 *         | IsAccessorField (bit 4)
70 *         | IsInlinedPropsField(bit 5)
71 *         | RepresentationField(bit 6...7)
72 *         --------------------------------
73 *    Fast | OffsetField(bit 8...17)
74 *         | TrackTypeField(bit 18...20)
75 *         | SharedFieldTypeField(bit 21...28)
76 *         | SortedIndexField(bit 29...38)
77 *         | IsConstPropsField(bit 39)
78 *         | IsNotHoleField(bit 40)
79 *         -----------------------------
80 *    Slow | PropertyBoxTypeField(bit 8...9)
81 *         | DictionaryOrderField(bit 10...29)
82 *         | SharedFieldTypeField(bit 30...37)
83 */
84class PropertyAttributes {
85public:
86    PropertyAttributes() = default;
87    ~PropertyAttributes() = default;
88
89    DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyAttributes);
90    DEFAULT_COPY_SEMANTIC(PropertyAttributes);
91
92    explicit PropertyAttributes(uint64_t v) : value_(v) {}
93    explicit PropertyAttributes(JSTaggedValue v) : value_(JSTaggedValue::UnwrapToUint64(v)) {}
94    explicit PropertyAttributes(const PropertyDescriptor &desc);
95
96    static constexpr uint32_t DICTIONARY_ORDER_NUM = 20;
97    static constexpr uint32_t OFFSET_BITFIELD_NUM = 10;
98    static constexpr uint32_t REPRESENTATION_NUM = 2;
99    static constexpr uint32_t TRACK_TYPE_NUM = 3;
100    static constexpr uint32_t FIELD_TYPE_NUM = 8;
101    static constexpr uint32_t MAX_FAST_PROPS_CAPACITY = (1U << OFFSET_BITFIELD_NUM) - 1;
102    static constexpr unsigned BITS_PER_BYTE = 8;
103
104    static constexpr uint32_t MAX_BIT_SIZE = 48;
105    static constexpr int INITIAL_PROPERTY_INDEX = 0;
106
107    using PropertyMetaDataField = BitField<int32_t, 0, 4>;  // 4: property metaData field occupies 4 bits
108    using AttributesField = BitField<int32_t, 0, 4>;        // 4: attributes field occupies 4 bits
109    using DefaultAttributesField = BitField<int32_t, 0, 3>; // 3: default attributes field occupies 3 bits
110    using WritableField = BitField<bool, 0, 1>;         // 1: writable field occupies 1 bits
111    using EnumerableField = WritableField::NextFlag;
112    using ConfigurableField = EnumerableField::NextFlag;
113    using IsAccessorField = ConfigurableField::NextFlag; // 4
114
115    using IsInlinedPropsField = PropertyMetaDataField::NextFlag;                                    // 5
116    using RepresentationField = IsInlinedPropsField::NextField<Representation, REPRESENTATION_NUM>; // 2: 2 bits, 6-7
117    using CommonLastBitField = RepresentationField;
118    // For flags required for both fast mode and slow mode, need to be added before CommonLastBitField
119
120    // ---------------------------------------------------------------------------------------------
121    // only for fast mode
122    using FastModeStartField = CommonLastBitField;
123    static_assert(FastModeStartField::START_BIT == CommonLastBitField::START_BIT);
124    static_assert(FastModeStartField::SIZE == CommonLastBitField::SIZE);
125    using OffsetField = FastModeStartField::NextField<uint32_t, OFFSET_BITFIELD_NUM>; // 17
126    using TrackTypeField = OffsetField::NextField<TrackType, TRACK_TYPE_NUM>;     // 20: 3 bits
127    static_assert(TrackTypeField::END_BIT <= sizeof(uint32_t) * BITS_PER_BYTE, "Invalid");
128
129    // normal attr should include SharedFieldTypeField when set to layout
130    static constexpr uint32_t NORMAL_ATTR_BITS = 28;
131    using NormalAttrField = BitField<uint32_t, 0, NORMAL_ATTR_BITS>;
132    using SharedFieldTypeField = TrackTypeField::NextField<SharedFieldType, FIELD_TYPE_NUM>; // 28: 8 bits
133    using SortedIndexField = SharedFieldTypeField::NextField<uint32_t, OFFSET_BITFIELD_NUM>; // 38: 10 bits
134    using IsConstPropsField = SortedIndexField::NextFlag;                              // 39
135    using IsNotHoleField = IsConstPropsField::NextFlag;                                // 40
136    using IsPGODumpedField = IsNotHoleField::NextFlag;                                      // 41
137    using FastModeLastField = IsPGODumpedField;
138    static_assert(
139        FastModeLastField::START_BIT + FastModeLastField::SIZE <= MAX_BIT_SIZE, "Invalid");
140
141    // ---------------------------------------------------------------------------------------------
142    // only for dictionary mode, include global
143    using DictModeStartField = CommonLastBitField;
144    static_assert(DictModeStartField::START_BIT == CommonLastBitField::START_BIT);
145    static_assert(DictModeStartField::SIZE == CommonLastBitField::SIZE);
146    using PropertyBoxTypeField = DictModeStartField::NextField<PropertyBoxType, 2>;               // 2: 2 bits, 8-9
147    using DictionaryOrderField = PropertyBoxTypeField::NextField<uint32_t, DICTIONARY_ORDER_NUM>; // 29
148    using DictSharedFieldTypeField = DictionaryOrderField::NextField<SharedFieldType, FIELD_TYPE_NUM>;
149    using DictModeLastField = DictSharedFieldTypeField;
150
151    static_assert(
152        DictModeLastField::START_BIT + DictModeLastField::SIZE <= MAX_BIT_SIZE, "Invalid");
153
154    inline int32_t GetPropertyMetaData() const
155    {
156        return PropertyMetaDataField::Get(value_);
157    }
158
159    static PropertyAttributes Default()
160    {
161        return PropertyAttributes(GetDefaultAttributes());
162    }
163
164    static PropertyAttributes Default(bool w, bool e, bool c, bool isAccessor = false)
165    {
166        uint64_t value = WritableField::Encode(w) | EnumerableField::Encode(e) | ConfigurableField::Encode(c) |
167                         IsAccessorField::Encode(isAccessor);
168        return PropertyAttributes(value);
169    }
170
171    static PropertyAttributes DefaultAccessor(bool w, bool e, bool c)
172    {
173        uint64_t value = WritableField::Encode(w) | EnumerableField::Encode(e) | ConfigurableField::Encode(c) |
174                         IsAccessorField::Encode(true);
175        return PropertyAttributes(value);
176    }
177
178    inline void SetDefaultAttributes()
179    {
180        AttributesField::Set<uint64_t>(DefaultAttributesField::Mask(), &value_);
181    }
182
183    static inline int32_t GetDefaultAttributes()
184    {
185        return DefaultAttributesField::Mask();
186    }
187    // JSShared should not update tracktype.
188    bool UpdateTrackType(JSTaggedValue value)
189    {
190        TrackType oldType = GetTrackType();
191        if (oldType == TrackType::TAGGED) {
192            return false;
193        }
194
195        TrackType newType = TrackType::TAGGED;
196        if (value.IsInt()) {
197            newType = static_cast<TrackType>(static_cast<uint8_t>(TrackType::INT) | static_cast<uint8_t>(oldType));
198        } else if (value.IsDouble()) {
199            newType = static_cast<TrackType>(static_cast<uint8_t>(TrackType::DOUBLE) | static_cast<uint8_t>(oldType));
200        }
201
202        if (oldType != newType) {
203            SetTrackType(newType);
204            return true;
205        }
206        return false;
207    }
208
209    inline bool IsDefaultAttributes() const
210    {
211        return AttributesField::Get(value_) == static_cast<int32_t>(DefaultAttributesField::Mask());
212    }
213
214    inline void SetNoneAttributes()
215    {
216        AttributesField::Set<uint64_t>(0U, &value_);
217    }
218
219    inline bool IsNoneAttributes() const
220    {
221        return AttributesField::Get(value_) == 0;
222    }
223
224    inline void SetWritable(bool flag)
225    {
226        WritableField::Set<uint64_t>(flag, &value_);
227    }
228    inline bool IsWritable() const
229    {
230        return WritableField::Get(value_);
231    }
232    inline void SetEnumerable(bool flag)
233    {
234        EnumerableField::Set<uint64_t>(flag, &value_);
235    }
236    inline bool IsEnumerable() const
237    {
238        return EnumerableField::Get(value_);
239    }
240    inline void SetConfigurable(bool flag)
241    {
242        ConfigurableField::Set<uint64_t>(flag, &value_);
243    }
244    inline bool IsConfigurable() const
245    {
246        return ConfigurableField::Get(value_);
247    }
248
249    inline void SetIsAccessor(bool flag)
250    {
251        IsAccessorField::Set<uint64_t>(flag, &value_);
252    }
253
254    inline bool IsAccessor() const
255    {
256        return IsAccessorField::Get(value_);
257    }
258
259    inline void SetIsInlinedProps(bool flag)
260    {
261        IsInlinedPropsField::Set<uint64_t>(flag, &value_);
262    }
263
264    inline bool IsInlinedProps() const
265    {
266        return IsInlinedPropsField::Get(value_);
267    }
268
269    inline void SetIsConstProps(bool flag)
270    {
271        IsConstPropsField::Set<uint64_t>(flag, &value_);
272    }
273
274    inline bool IsConstProps() const
275    {
276        return IsConstPropsField::Get(value_);
277    }
278
279    inline void SetIsNotHole(bool flag)
280    {
281        IsNotHoleField::Set<uint64_t>(flag, &value_);
282    }
283
284    inline bool IsNotHole() const
285    {
286        return IsNotHoleField::Get(value_);
287    }
288
289    inline bool IsTaggedRep() const
290    {
291        return !IsDoubleRep() && !IsIntRep();
292    }
293
294    inline bool IsDoubleRep() const
295    {
296        auto rep = GetRepresentation();
297        return rep == Representation::DOUBLE;
298    }
299
300    inline bool IsIntRep() const
301    {
302        auto rep = GetRepresentation();
303        return rep == Representation::INT;
304    }
305
306    inline void SetRepresentation(Representation representation)
307    {
308        RepresentationField::Set<uint64_t>(representation, &value_);
309    }
310
311    inline Representation GetRepresentation() const
312    {
313        return RepresentationField::Get(value_);
314    }
315
316    inline TrackType GetTrackType() const
317    {
318        return TrackTypeField::Get(value_);
319    }
320
321    inline void SetTrackType(TrackType type)
322    {
323        TrackTypeField::Set<uint64_t>(type, &value_);
324    }
325
326    inline bool IsPGODumped()
327    {
328        return IsPGODumpedField::Get(value_);
329    }
330
331    inline void SetIsPGODumped(bool isDumped)
332    {
333        IsPGODumpedField::Set<uint64_t>(isDumped, &value_);
334    }
335
336    inline SharedFieldType GetSharedFieldType() const
337    {
338        return SharedFieldTypeField::Get(value_);
339    }
340
341    inline void SetSharedFieldType(SharedFieldType fieldType)
342    {
343        SharedFieldTypeField::Set<uint64_t>(fieldType, &value_);
344    }
345
346    inline void SetDictSharedFieldType(SharedFieldType fieldType)
347    {
348        DictSharedFieldTypeField::Set<uint64_t>(fieldType, &value_);
349    }
350
351    inline SharedFieldType GetDictSharedFieldType() const
352    {
353        return DictSharedFieldTypeField::Get(value_);
354    }
355
356    inline void SetDictionaryOrder(uint32_t order)
357    {
358        DictionaryOrderField::Set<uint64_t>(order, &value_);
359    }
360    inline uint32_t GetDictionaryOrder() const
361    {
362        return DictionaryOrderField::Get(value_);
363    }
364
365    inline void SetOffset(uint32_t offset)
366    {
367        OffsetField::Set<uint64_t>(offset, &value_);
368    }
369
370    inline uint32_t GetOffset() const
371    {
372        return OffsetField::Get(value_);
373    }
374
375    inline void SetSortedIndex(uint32_t sortedIndex)
376    {
377        SortedIndexField::Set<uint64_t>(sortedIndex, &value_);
378    }
379    inline uint32_t GetSortedIndex() const
380    {
381        return SortedIndexField::Get(value_);
382    }
383
384    inline void SetNormalAttr(uint32_t normalAttr)
385    {
386        NormalAttrField::Set<uint64_t>(normalAttr, &value_);
387    }
388
389    inline uint32_t GetNormalAttr() const
390    {
391        return NormalAttrField::Get(value_);
392    }
393
394    inline JSTaggedValue GetNormalTagged() const
395    {
396        return JSTaggedValue::WrapUint64(GetNormalAttr());
397    }
398
399    inline uint64_t GetValue() const
400    {
401        return value_;
402    }
403
404    inline void SetBoxType(PropertyBoxType cellType)
405    {
406        PropertyBoxTypeField::Set<uint64_t>(cellType, &value_);
407    }
408
409    inline PropertyBoxType GetBoxType() const
410    {
411        return PropertyBoxTypeField::Get(value_);
412    }
413
414    static inline Representation TranslateToRep(JSTaggedValue value)
415    {
416        if (value.IsInt()) {
417            return Representation::INT;
418        } else if (value.IsDouble()) {
419            return Representation::DOUBLE;
420        }
421        return Representation::TAGGED;
422    }
423
424    inline static bool IsValidIndex(int index)
425    {
426        return DictionaryOrderField::IsValid(index);
427    }
428
429    inline JSTaggedValue GetTaggedValue() const
430    {
431        return JSTaggedValue::WrapUint64(value_);
432    }
433
434private:
435    uint64_t value_{0};
436};
437}  // namespace panda::ecmascript
438#endif  // ECMASCRIPT_PROPERTY_ATTRIBUTES_H
439