1 /* 2 * Copyright (c) 2021-2024 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_IC_IC_HANDLER_H 17 #define ECMASCRIPT_IC_IC_HANDLER_H 18 19 #include "ecmascript/ecma_macros.h" 20 #include "ecmascript/js_tagged_value-inl.h" 21 #include "ecmascript/js_typed_array.h" 22 #include "ecmascript/mem/tagged_object.h" 23 #include "ecmascript/object_operator.h" 24 #include "ecmascript/js_function.h" 25 26 namespace panda::ecmascript { 27 class HandlerBase { 28 public: 29 static constexpr uint32_t KIND_BIT_LENGTH = 4; 30 static constexpr uint32_t STORE_KIND_BIT_LENGTH = 2; 31 static constexpr uint32_t MAX_BIT_SIZE = 48; 32 enum HandlerKind { 33 NONE = 0, 34 FIELD, 35 ELEMENT, 36 DICTIONARY, 37 STRING, 38 STRING_LENGTH, 39 TYPED_ARRAY, 40 NUMBER, 41 NON_EXIST, 42 TOTAL_KINDS, 43 }; 44 static_assert(static_cast<size_t>(HandlerKind::TOTAL_KINDS) <= (1 << KIND_BIT_LENGTH)); 45 46 // Store Handler kind combined with KindBit called SWholeKindBit. Which used to quickly check S_FIELD kind 47 enum StoreHandlerKind { 48 S_NONE = HandlerKind::NONE, 49 S_FIELD, 50 S_ELEMENT, 51 S_TOTAL_KINDS, 52 }; 53 static_assert(static_cast<size_t>(StoreHandlerKind::S_TOTAL_KINDS) <= (1 << STORE_KIND_BIT_LENGTH)); 54 55 // For Load 56 using KindBit = BitField<HandlerKind, 0, KIND_BIT_LENGTH>; // [0, 4) 57 using InlinedPropsBit = KindBit::NextFlag; // [4, 5) 58 using AccessorBit = InlinedPropsBit::NextFlag; // [5, 6) 59 using IsJSArrayBit = AccessorBit::NextFlag; // [6, 7) 60 using OffsetBit = IsJSArrayBit::NextField<uint32_t, PropertyAttributes::MAX_FAST_PROPS_CAPACITY_LOG2>; // [7, 17) 61 using RepresentationBit = OffsetBit::NextField<Representation, PropertyAttributes::REPRESENTATION_NUM>; // [17, 19) 62 using AttrIndexBit = 63 RepresentationBit::NextField<uint32_t, PropertyAttributes::MAX_FAST_PROPS_CAPACITY_LOG2>; // [19, 29) 64 using IsOnHeapBit = AttrIndexBit::NextFlag; // [29, 30) 65 using NeedSkipInPGODumpBit = IsOnHeapBit::NextFlag; // [30, 31) 66 static_assert(NeedSkipInPGODumpBit::END_BIT <= MAX_BIT_SIZE, "load handler overflow"); 67 68 // For Store 69 using SWholeKindBit = KindBit; 70 using SKindBit = BitField<StoreHandlerKind, 0, STORE_KIND_BIT_LENGTH>; // [0, 2) 71 static_assert(SKindBit::START_BIT == KindBit::START_BIT); 72 using SSharedBit = SKindBit::NextFlag; // [2, 4) 73 static_assert((SKindBit::SIZE + SSharedBit::SIZE) <= KindBit::SIZE); // reuse: [0, 4) bits 74 // shared with Load bits: [4, 30) 75 using SOutOfBoundsBit = IsOnHeapBit::NextFlag; // reuse: [30, 31) bit 76 using SFieldTypeBit = SOutOfBoundsBit::NextField<SharedFieldType, PropertyAttributes::FIELD_TYPE_NUM>; // [31, 39) 77 static_assert(SFieldTypeBit::END_BIT <= MAX_BIT_SIZE, "store handler overflow"); 78 using Type = uint64_t; 79 static_assert(sizeof(Type) <= JSTaggedValue::TaggedTypeSize()); 80 81 HandlerBase() = default; 82 virtual ~HandlerBase() = default; 83 IsAccessor(Type handler)84 static inline bool IsAccessor(Type handler) 85 { 86 return AccessorBit::Get(handler); 87 } 88 GetFieldType(Type handler)89 static inline SharedFieldType GetFieldType(Type handler) 90 { 91 return static_cast<SharedFieldType>(SFieldTypeBit::Get(handler)); 92 } 93 IsNonExist(Type handler)94 static inline bool IsNonExist(Type handler) 95 { 96 return GetKind(handler) == HandlerKind::NON_EXIST; 97 } 98 IsField(Type handler)99 static inline bool IsField(Type handler) 100 { 101 return GetKind(handler) == HandlerKind::FIELD; 102 } 103 IsNonSharedStoreField(Type handler)104 static inline bool IsNonSharedStoreField(Type handler) 105 { 106 return static_cast<StoreHandlerKind>(GetKind(handler)) == StoreHandlerKind::S_FIELD; 107 } 108 IsStoreShared(Type handler)109 static inline bool IsStoreShared(Type handler) 110 { 111 return SSharedBit::Get(handler); 112 } 113 ClearSharedStoreKind(Type & handler)114 static inline void ClearSharedStoreKind(Type &handler) 115 { 116 SSharedBit::Set<Type>(false, &handler); 117 } 118 IsStoreOutOfBounds(Type handler)119 static inline bool IsStoreOutOfBounds(Type handler) 120 { 121 return SOutOfBoundsBit::Get(handler); 122 } 123 ClearStoreOutOfBounds(Type & handler)124 static inline void ClearStoreOutOfBounds(Type &handler) 125 { 126 SOutOfBoundsBit::Set<Type>(false, &handler); 127 } 128 IsString(Type handler)129 static inline bool IsString(Type handler) 130 { 131 return GetKind(handler) == HandlerKind::STRING; 132 } 133 IsNumber(Type handler)134 static inline bool IsNumber(Type handler) 135 { 136 return GetKind(handler) == HandlerKind::NUMBER; 137 } 138 IsStringLength(Type handler)139 static inline bool IsStringLength(Type handler) 140 { 141 return GetKind(handler) == HandlerKind::STRING_LENGTH; 142 } 143 IsElement(Type handler)144 static inline bool IsElement(Type handler) 145 { 146 return IsNormalElement(handler) || IsStringElement(handler) || IsTypedArrayElement(handler); 147 } 148 IsNormalElement(Type handler)149 static inline bool IsNormalElement(Type handler) 150 { 151 return GetKind(handler) == HandlerKind::ELEMENT; 152 } 153 IsStringElement(Type handler)154 static inline bool IsStringElement(Type handler) 155 { 156 return GetKind(handler) == HandlerKind::STRING; 157 } 158 IsTypedArrayElement(Type handler)159 static inline bool IsTypedArrayElement(Type handler) 160 { 161 return GetKind(handler) == HandlerKind::TYPED_ARRAY; 162 } 163 IsDictionary(Type handler)164 static inline bool IsDictionary(Type handler) 165 { 166 return GetKind(handler) == HandlerKind::DICTIONARY; 167 } 168 IsInlinedProps(Type handler)169 static inline bool IsInlinedProps(Type handler) 170 { 171 return InlinedPropsBit::Get(handler); 172 } 173 GetKind(Type handler)174 static inline HandlerKind GetKind(Type handler) 175 { 176 return KindBit::Get(handler); 177 } 178 IsJSArray(Type handler)179 static inline bool IsJSArray(Type handler) 180 { 181 return IsJSArrayBit::Get(handler); 182 } 183 NeedSkipInPGODump(Type handler)184 static inline bool NeedSkipInPGODump(Type handler) 185 { 186 return NeedSkipInPGODumpBit::Get(handler); 187 } 188 GetOffset(Type handler)189 static inline int GetOffset(Type handler) 190 { 191 return OffsetBit::Get(handler); 192 } 193 IsOnHeap(Type handler)194 static inline bool IsOnHeap(Type handler) 195 { 196 return IsOnHeapBit::Get(handler); 197 } 198 199 static void PrintLoadHandler(uint64_t handler, std::ostream& os); 200 static void PrintStoreHandler(uint64_t handler, std::ostream& os); 201 }; 202 203 class LoadHandler final : public HandlerBase { 204 public: 205 static JSHandle<JSTaggedValue> LoadProperty(const JSThread *thread, const ObjectOperator &op); 206 static JSHandle<JSTaggedValue> LoadElement(const JSThread *thread, const ObjectOperator &op); 207 LoadStringElement(const JSThread * thread)208 static inline JSHandle<JSTaggedValue> LoadStringElement(const JSThread *thread) 209 { 210 uint64_t handler = 0; 211 KindBit::Set<uint64_t>(HandlerKind::STRING, &handler); 212 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 213 } 214 LoadTypedArrayElement(const JSThread * thread,JSHandle<JSTypedArray> typedArray)215 static inline JSHandle<JSTaggedValue> LoadTypedArrayElement(const JSThread *thread, 216 JSHandle<JSTypedArray> typedArray) 217 { 218 uint64_t handler = 0; 219 KindBit::Set<uint64_t>(HandlerKind::TYPED_ARRAY, &handler); 220 IsOnHeapBit::Set<uint64_t>(JSHandle<TaggedObject>(typedArray)->GetClass()->IsOnHeapFromBitField(), &handler); 221 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 222 } 223 }; 224 225 class StoreHandler final : public HandlerBase { 226 public: 227 static JSHandle<JSTaggedValue> StoreProperty(const JSThread *thread, const ObjectOperator &op); 228 StoreElement(const JSThread * thread,JSHandle<JSTaggedValue> receiver,uint64_t handler)229 static inline JSHandle<JSTaggedValue> StoreElement(const JSThread *thread, 230 JSHandle<JSTaggedValue> receiver, uint64_t handler) 231 { 232 SKindBit::Set<uint64_t>(StoreHandlerKind::S_ELEMENT, &handler); 233 234 if (receiver->IsJSArray()) { 235 IsJSArrayBit::Set<uint64_t>(true, &handler); 236 } 237 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 238 } 239 SFieldTypeBitSet(const ObjectOperator & op,JSHandle<JSObject> & receiver,uint64_t * handler)240 static inline void SFieldTypeBitSet(const ObjectOperator &op, JSHandle<JSObject> &receiver, uint64_t *handler) 241 { 242 SSharedBit::Set<uint64_t>(op.GetReceiver()->IsJSShared(), handler); 243 TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject()); 244 if (!array->IsDictionaryMode()) { 245 SFieldTypeBit::Set<uint64_t>(op.GetAttr().GetSharedFieldType(), handler); 246 } else { 247 SFieldTypeBit::Set<uint64_t>(op.GetAttr().GetDictSharedFieldType(), handler); 248 } 249 } 250 }; 251 252 class TransitionHandler : public TaggedObject { 253 public: Cast(TaggedObject * object)254 static TransitionHandler *Cast(TaggedObject *object) 255 { 256 ASSERT(JSTaggedValue(object).IsTransitionHandler()); 257 return static_cast<TransitionHandler *>(object); 258 } 259 260 static JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op); 261 262 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 263 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET) 264 ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, SIZE) 265 266 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) 267 DECL_DUMP() 268 }; 269 270 class PrototypeHandler : public TaggedObject { 271 public: Cast(TaggedObject * object)272 static PrototypeHandler *Cast(TaggedObject *object) 273 { 274 ASSERT(JSTaggedValue(object).IsPrototypeHandler()); 275 return static_cast<PrototypeHandler *>(object); 276 } 277 278 static JSHandle<JSTaggedValue> LoadPrototype(const JSThread *thread, const ObjectOperator &op, 279 const JSHandle<JSHClass> &hclass); 280 static JSHandle<JSTaggedValue> StorePrototype(const JSThread *thread, const ObjectOperator &op, 281 const JSHandle<JSHClass> &hclass); 282 283 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 284 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET) 285 ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET) 286 ACCESSORS(Holder, HOLDER_OFFSET, ACCESSOR_JSFUNCTION_OFFSET) 287 ACCESSORS(AccessorJSFunction, ACCESSOR_JSFUNCTION_OFFSET, ACCESSOR_METHOD_ID_OFFSET) 288 ACCESSORS_PRIMITIVE_FIELD(AccessorMethodId, uint32_t, ACCESSOR_METHOD_ID_OFFSET, LAST_OFFSET) 289 290 DEFINE_ALIGN_SIZE(LAST_OFFSET); 291 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, ACCESSOR_METHOD_ID_OFFSET) 292 DECL_DUMP() 293 }; 294 295 class TransWithProtoHandler : public TaggedObject { 296 public: Cast(TaggedObject * object)297 static TransWithProtoHandler *Cast(TaggedObject *object) 298 { 299 ASSERT(JSTaggedValue(object).IsTransWithProtoHandler()); 300 return static_cast<TransWithProtoHandler *>(object); 301 } 302 303 static JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op, 304 const JSHandle<JSHClass> &hclass); 305 306 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 307 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET) 308 ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, PROTO_CELL_OFFSET) 309 ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, SIZE) 310 311 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) 312 DECL_DUMP() 313 }; 314 315 class StoreAOTHandler : public TaggedObject { 316 public: Cast(TaggedObject * object)317 static StoreAOTHandler *Cast(TaggedObject *object) 318 { 319 ASSERT(JSTaggedValue(object).IsStoreAOTHandler()); 320 return static_cast<StoreAOTHandler *>(object); 321 } 322 323 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 324 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET) 325 ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET) 326 ACCESSORS(Holder, HOLDER_OFFSET, SIZE) 327 328 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) 329 DECL_DUMP() 330 }; 331 } // namespace panda::ecmascript 332 #endif // ECMASCRIPT_IC_IC_HANDLER_H 333