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