1/*
2 * Copyright (c) 2023 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_ELEMENTS_H
17#define ECMASCRIPT_ELEMENTS_H
18
19#include "ecmascript/global_env_constants.h"
20#include "ecmascript/js_tagged_value.h"
21#include "ecmascript/mem/c_containers.h"
22
23namespace panda::ecmascript {
24
25#define ELEMENTS_KIND_INIT_HCLASS_LIST(V)           \
26    V(NONE)                                         \
27    V(HOLE)                                         \
28    V(INT)                                          \
29    V(NUMBER)                                       \
30    V(STRING)                                       \
31    V(OBJECT)                                       \
32    V(TAGGED)                                       \
33    V(HOLE_INT)                                     \
34    V(HOLE_NUMBER)                                  \
35    V(HOLE_STRING)                                  \
36    V(HOLE_OBJECT)                                  \
37    V(HOLE_TAGGED)
38
39enum class ElementsKind : uint8_t {
40    NONE = 0x00UL,
41    HOLE = 0x01UL,
42    INT = 0x1UL << 1,      // 2
43    NUMBER = (0x1UL << 2) | INT, // 6
44    STRING = 0x1UL << 3,   // 8
45    OBJECT = 0x1UL << 4,   // 16
46    TAGGED = 0x1EUL,       // 30
47    HOLE_INT = HOLE | INT,
48    HOLE_NUMBER = HOLE | NUMBER,
49    HOLE_STRING = HOLE | STRING,
50    HOLE_OBJECT = HOLE | OBJECT,
51    HOLE_TAGGED = HOLE | TAGGED,
52    GENERIC = HOLE_TAGGED,
53    DICTIONARY = HOLE_TAGGED,
54};
55
56class PUBLIC_API Elements {
57public:
58    static CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> InitializeHClassMap();
59
60    static std::string GetString(ElementsKind kind);
61    static bool IsInt(ElementsKind kind);
62    static bool IsNumber(ElementsKind kind);
63    static bool IsTagged(ElementsKind kind);
64    static bool IsObject(ElementsKind kind);
65    static bool IsHole(ElementsKind kind);
66    static bool IsGeneric(ElementsKind kind)
67    {
68        return kind == ElementsKind::GENERIC;
69    }
70
71    static bool IsNone(ElementsKind kind)
72    {
73        return kind == ElementsKind::NONE;
74    }
75
76    static bool IsComplex(ElementsKind kind)
77    {
78        return IsNumber(kind) || IsTagged(kind);
79    }
80
81    static bool IsInNumbers(ElementsKind kind)
82    {
83        return (static_cast<uint32_t>(kind) > static_cast<uint32_t>(ElementsKind::HOLE) &&
84                static_cast<uint32_t>(kind) < static_cast<uint32_t>(ElementsKind::STRING));
85    }
86
87    static bool IsHoleInt(ElementsKind kind)
88    {
89        return kind == ElementsKind::HOLE_INT;
90    }
91
92    static bool IsHoleNumber(ElementsKind kind)
93    {
94        return kind == ElementsKind::HOLE_NUMBER;
95    }
96
97    static ConstantIndex GetGlobalContantIndexByKind(ElementsKind kind);
98    static ElementsKind MergeElementsKind(ElementsKind curKind, ElementsKind newKind);
99    static ElementsKind FixElementsKind(ElementsKind oldKind);
100    static ElementsKind ToElementsKind(JSTaggedValue value, ElementsKind kind);
101    static void MigrateArrayWithKind(const JSThread *thread, const JSHandle<JSObject> &object,
102                                     const ElementsKind oldKind, const ElementsKind newKind);
103private:
104    static JSTaggedValue MigrateFromRawValueToHeapValue(const JSThread *thread, const JSHandle<JSObject> object,
105                                                         bool needCOW, bool isIntKind);
106    static void HandleIntKindMigration(const JSThread *thread, const JSHandle<JSObject> &object,
107                                       const ElementsKind newKind, bool needCOW);
108    static bool IsNumberKind(const ElementsKind kind);
109    static bool IsStringOrNoneOrHole(const ElementsKind kind);
110    static void HandleNumberKindMigration(const JSThread *thread,
111                                          const JSHandle<JSObject> &object,
112                                          const ElementsKind newKind, bool needCOW);
113    static void HandleOtherKindMigration(const JSThread *thread, const JSHandle<JSObject> &object,
114                                         const ElementsKind newKind, bool needCOW);
115    static JSTaggedValue MigrateFromHeapValueToRawValue(const JSThread *thread, const JSHandle<JSObject> object,
116                                                        bool needCOW, bool isIntKind);
117    static void MigrateFromHoleIntToHoleNumber(const JSThread *thread, const JSHandle<JSObject> object);
118    static void MigrateFromHoleNumberToHoleInt(const JSThread *thread, const JSHandle<JSObject> object);
119
120};
121}  // namespace panda::ecmascript
122#endif // ECMASCRIPT_ELEMENTS_H
123