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, // 0 41 HOLE = 0x01UL, // 1 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, // 3 48 HOLE_NUMBER = HOLE | NUMBER, // 7 49 HOLE_STRING = HOLE | STRING, // 9 50 HOLE_OBJECT = HOLE | OBJECT, // 17 51 HOLE_TAGGED = HOLE | TAGGED, // 31 52 GENERIC = HOLE_TAGGED, 53 DICTIONARY = HOLE_TAGGED, 54 }; 55 56 class PUBLIC_API Elements { 57 public: 58 static constexpr int32_t KIND_COUNT = static_cast<uint8_t>(ElementsKind::HOLE_TAGGED) + 1; 59 ToUint(ElementsKind kind)60 static constexpr uint32_t ToUint(ElementsKind kind) 61 { 62 return static_cast<uint32_t>(kind); 63 } 64 static std::string GetString(ElementsKind kind); 65 static bool IsInt(ElementsKind kind); 66 static bool IsNumber(ElementsKind kind); 67 static bool IsTagged(ElementsKind kind); 68 static bool IsObject(ElementsKind kind); 69 static bool IsHole(ElementsKind kind); IsGeneric(ElementsKind kind)70 static bool IsGeneric(ElementsKind kind) 71 { 72 return kind == ElementsKind::GENERIC; 73 } 74 IsNone(ElementsKind kind)75 static bool IsNone(ElementsKind kind) 76 { 77 return kind == ElementsKind::NONE; 78 } 79 IsComplex(ElementsKind kind)80 static bool IsComplex(ElementsKind kind) 81 { 82 return IsNumber(kind) || IsTagged(kind); 83 } 84 IsInNumbers(ElementsKind kind)85 static bool IsInNumbers(ElementsKind kind) 86 { 87 return (ToUint(kind) > ToUint(ElementsKind::HOLE) && 88 ToUint(kind) < ToUint(ElementsKind::STRING)); 89 } 90 IsIntOrHoleInt(ElementsKind kind)91 static bool IsIntOrHoleInt(ElementsKind kind) 92 { 93 return kind == ElementsKind::INT || kind == ElementsKind::HOLE_INT; 94 } 95 IsNumberOrHoleNumber(ElementsKind kind)96 static bool IsNumberOrHoleNumber(ElementsKind kind) 97 { 98 return kind == ElementsKind::NUMBER || kind == ElementsKind::HOLE_NUMBER; 99 } 100 IsStringOrHoleString(ElementsKind kind)101 static bool IsStringOrHoleString(ElementsKind kind) 102 { 103 return kind == ElementsKind::STRING || kind == ElementsKind::HOLE_STRING; 104 } 105 106 static ConstantIndex GetGlobalContantIndexByKind(ElementsKind kind); 107 static ElementsKind MergeElementsKind(ElementsKind curKind, ElementsKind newKind); 108 static ElementsKind FixElementsKind(ElementsKind oldKind); ToElementsKind(JSTaggedValue value)109 static inline ElementsKind ToElementsKind(JSTaggedValue value) 110 { 111 ElementsKind valueKind = ElementsKind::NONE; 112 if (value.IsInt()) { 113 valueKind = ElementsKind::INT; 114 } else if (value.IsDouble()) { 115 valueKind = ElementsKind::NUMBER; 116 } else if (value.IsString()) { 117 valueKind = ElementsKind::STRING; 118 } else if (value.IsHeapObject()) { 119 valueKind = ElementsKind::OBJECT; 120 } else if (value.IsHole()) { 121 valueKind = ElementsKind::HOLE; 122 } else { 123 valueKind = ElementsKind::TAGGED; 124 } 125 return valueKind; 126 } 127 static ElementsKind ToElementsKind(JSTaggedValue value, ElementsKind kind); 128 MergeElementsKindNoFix(JSTaggedValue value,ElementsKind curKind,ElementsKind newKind)129 static ElementsKind MergeElementsKindNoFix(JSTaggedValue value, ElementsKind curKind, ElementsKind newKind) 130 { 131 return static_cast<ElementsKind>(static_cast<uint8_t>(ToElementsKind(value)) | static_cast<uint8_t>(curKind) | 132 static_cast<uint8_t>(newKind)); 133 } 134 135 static void MigrateArrayWithKind(const JSThread *thread, const JSHandle<JSObject> &object, 136 const ElementsKind oldKind, const ElementsKind newKind); 137 private: 138 static JSTaggedValue MigrateFromRawValueToHeapValue(const JSThread *thread, const JSHandle<JSObject> object, 139 bool needCOW, bool isIntKind); 140 static void HandleIntKindMigration(const JSThread *thread, const JSHandle<JSObject> &object, 141 const ElementsKind newKind, bool needCOW); 142 static bool IsNumberKind(const ElementsKind kind); 143 static bool IsStringOrNoneOrHole(const ElementsKind kind); 144 static void HandleNumberKindMigration(const JSThread *thread, 145 const JSHandle<JSObject> &object, 146 const ElementsKind newKind, bool needCOW); 147 static void HandleOtherKindMigration(const JSThread *thread, const JSHandle<JSObject> &object, 148 const ElementsKind newKind, bool needCOW); 149 static JSTaggedValue MigrateFromHeapValueToRawValue(const JSThread *thread, const JSHandle<JSObject> object, 150 bool needCOW, bool isIntKind); 151 static void MigrateFromHoleIntToHoleNumber(const JSThread *thread, const JSHandle<JSObject> object); 152 static void MigrateFromHoleNumberToHoleInt(const JSThread *thread, const JSHandle<JSObject> object); 153 154 }; 155 } // namespace panda::ecmascript 156 #endif // ECMASCRIPT_ELEMENTS_H 157