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_fields.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 ElementsKind MergeElementsKind(ElementsKind curKind, ElementsKind newKind); 107 static ElementsKind FixElementsKind(ElementsKind oldKind); ToElementsKind(JSTaggedValue value)108 static inline ElementsKind ToElementsKind(JSTaggedValue value) 109 { 110 ElementsKind valueKind = ElementsKind::NONE; 111 if (value.IsInt()) { 112 valueKind = ElementsKind::INT; 113 } else if (value.IsDouble()) { 114 valueKind = ElementsKind::NUMBER; 115 } else if (value.IsString()) { 116 valueKind = ElementsKind::STRING; 117 } else if (value.IsHeapObject()) { 118 valueKind = ElementsKind::OBJECT; 119 } else if (value.IsHole()) { 120 valueKind = ElementsKind::HOLE; 121 } else { 122 valueKind = ElementsKind::TAGGED; 123 } 124 return valueKind; 125 } 126 static ElementsKind ToElementsKind(JSTaggedValue value, ElementsKind kind); 127 MergeElementsKindNoFix(JSTaggedValue value,ElementsKind curKind,ElementsKind newKind)128 static ElementsKind MergeElementsKindNoFix(JSTaggedValue value, ElementsKind curKind, ElementsKind newKind) 129 { 130 return static_cast<ElementsKind>(static_cast<uint8_t>(ToElementsKind(value)) | static_cast<uint8_t>(curKind) | 131 static_cast<uint8_t>(newKind)); 132 } 133 134 static void MigrateArrayWithKind(const JSThread *thread, const JSHandle<JSObject> &object, 135 const ElementsKind oldKind, const ElementsKind newKind); 136 private: 137 static JSTaggedValue MigrateFromRawValueToHeapValue(const JSThread *thread, const JSHandle<JSObject> object, 138 bool needCOW, bool isIntKind); 139 static void HandleIntKindMigration(const JSThread *thread, const JSHandle<JSObject> &object, 140 const ElementsKind newKind, bool needCOW); 141 static bool IsNumberKind(const ElementsKind kind); 142 static bool IsStringOrNoneOrHole(const ElementsKind kind); 143 static void HandleNumberKindMigration(const JSThread *thread, 144 const JSHandle<JSObject> &object, 145 const ElementsKind newKind, bool needCOW); 146 static void HandleOtherKindMigration(const JSThread *thread, const JSHandle<JSObject> &object, 147 const ElementsKind newKind, bool needCOW); 148 static JSTaggedValue MigrateFromHeapValueToRawValue(const JSThread *thread, const JSHandle<JSObject> object, 149 bool needCOW, bool isIntKind); 150 static void MigrateFromHoleIntToHoleNumber(const JSThread *thread, const JSHandle<JSObject> object); 151 static void MigrateFromHoleNumberToHoleInt(const JSThread *thread, const JSHandle<JSObject> object); 152 153 }; 154 } // namespace panda::ecmascript 155 #endif // ECMASCRIPT_ELEMENTS_H 156