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 
23 namespace 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 
39 enum 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 
56 class PUBLIC_API Elements {
57 public:
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);
IsGeneric(ElementsKind kind)66     static bool IsGeneric(ElementsKind kind)
67     {
68         return kind == ElementsKind::GENERIC;
69     }
70 
IsNone(ElementsKind kind)71     static bool IsNone(ElementsKind kind)
72     {
73         return kind == ElementsKind::NONE;
74     }
75 
IsComplex(ElementsKind kind)76     static bool IsComplex(ElementsKind kind)
77     {
78         return IsNumber(kind) || IsTagged(kind);
79     }
80 
IsInNumbers(ElementsKind kind)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 
IsHoleInt(ElementsKind kind)87     static bool IsHoleInt(ElementsKind kind)
88     {
89         return kind == ElementsKind::HOLE_INT;
90     }
91 
IsHoleNumber(ElementsKind kind)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);
103 private:
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