1 /* 2 * Copyright (c) 2021 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/mem/tagged_object.h" 22 23 namespace panda::ecmascript { 24 class HandlerBase { 25 public: 26 static constexpr uint32_t KIND_BIT_LENGTH = 3; 27 enum HandlerKind { 28 NONE = 0, 29 FIELD, 30 ELEMENT, 31 DICTIONARY, 32 NON_EXIST, 33 }; 34 35 using KindBit = BitField<HandlerKind, 0, KIND_BIT_LENGTH>; 36 using InlinedPropsBit = KindBit::NextFlag; 37 using AccessorBit = InlinedPropsBit::NextFlag; 38 using InternalAccessorBit = AccessorBit::NextFlag; 39 using IsJSArrayBit = InternalAccessorBit::NextFlag; 40 using OffsetBit = IsJSArrayBit::NextField<uint32_t, PropertyAttributes::OFFSET_BITFIELD_NUM>; 41 42 HandlerBase() = default; 43 virtual ~HandlerBase() = default; 44 IsAccessor(uint32_t handler)45 static inline bool IsAccessor(uint32_t handler) 46 { 47 return AccessorBit::Get(handler); 48 } 49 IsInternalAccessor(uint32_t handler)50 static inline bool IsInternalAccessor(uint32_t handler) 51 { 52 return InternalAccessorBit::Get(handler); 53 } 54 IsNonExist(uint32_t handler)55 static inline bool IsNonExist(uint32_t handler) 56 { 57 return GetKind(handler) == HandlerKind::NON_EXIST; 58 } 59 IsField(uint32_t handler)60 static inline bool IsField(uint32_t handler) 61 { 62 return GetKind(handler) == HandlerKind::FIELD; 63 } 64 IsElement(uint32_t handler)65 static inline bool IsElement(uint32_t handler) 66 { 67 return GetKind(handler) == HandlerKind::ELEMENT; 68 } 69 IsDictionary(uint32_t handler)70 static inline bool IsDictionary(uint32_t handler) 71 { 72 return GetKind(handler) == HandlerKind::DICTIONARY; 73 } 74 IsInlinedProps(uint32_t handler)75 static inline bool IsInlinedProps(uint32_t handler) 76 { 77 return InlinedPropsBit::Get(handler); 78 } 79 GetKind(uint32_t handler)80 static inline HandlerKind GetKind(uint32_t handler) 81 { 82 return KindBit::Get(handler); 83 } 84 IsJSArray(uint32_t handler)85 static inline bool IsJSArray(uint32_t handler) 86 { 87 return IsJSArrayBit::Get(handler); 88 } 89 GetOffset(uint32_t handler)90 static inline int GetOffset(uint32_t handler) 91 { 92 return OffsetBit::Get(handler); 93 } 94 }; 95 96 class LoadHandler final : public HandlerBase { 97 public: LoadProperty(const JSThread * thread,const ObjectOperator & op)98 static inline JSHandle<JSTaggedValue> LoadProperty(const JSThread *thread, const ObjectOperator &op) 99 { 100 uint32_t handler = 0; 101 ASSERT(!op.IsElement()); 102 if (!op.IsFound()) { 103 KindBit::Set<uint32_t>(HandlerKind::NON_EXIST, &handler); 104 return JSHandle<JSTaggedValue>(thread, JSTaggedValue(handler)); 105 } 106 ASSERT(op.IsFastMode()); 107 108 JSTaggedValue val = op.GetValue(); 109 if (val.IsPropertyBox()) { 110 return JSHandle<JSTaggedValue>(thread, val); 111 } 112 bool hasAccessor = op.IsAccessorDescriptor(); 113 AccessorBit::Set<uint32_t>(hasAccessor, &handler); 114 if (!hasAccessor) { 115 KindBit::Set<uint32_t>(HandlerKind::FIELD, &handler); 116 } 117 118 if (op.IsInlinedProps()) { 119 InlinedPropsBit::Set<uint32_t>(true, &handler); 120 JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder()); 121 auto index = holder->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex()); 122 OffsetBit::Set<uint32_t>(index, &handler); 123 return JSHandle<JSTaggedValue>(thread, JSTaggedValue(handler)); 124 } 125 if (op.IsFastMode()) { 126 OffsetBit::Set<uint32_t>(op.GetIndex(), &handler); 127 return JSHandle<JSTaggedValue>(thread, JSTaggedValue(handler)); 128 } 129 UNREACHABLE(); 130 } 131 LoadElement(const JSThread * thread)132 static inline JSHandle<JSTaggedValue> LoadElement(const JSThread *thread) 133 { 134 uint32_t handler = 0; 135 KindBit::Set<uint32_t>(HandlerKind::ELEMENT, &handler); 136 return JSHandle<JSTaggedValue>(thread, JSTaggedValue(handler)); 137 } 138 }; 139 140 class StoreHandler final : public HandlerBase { 141 public: StoreProperty(const JSThread * thread,const ObjectOperator & op)142 static inline JSHandle<JSTaggedValue> StoreProperty(const JSThread *thread, const ObjectOperator &op) 143 { 144 if (op.IsElement()) { 145 return StoreElement(thread, op.GetReceiver()); 146 } 147 uint32_t handler = 0; 148 JSTaggedValue val = op.GetValue(); 149 if (val.IsPropertyBox()) { 150 return JSHandle<JSTaggedValue>(thread, val); 151 } 152 bool hasSetter = op.IsAccessorDescriptor(); 153 AccessorBit::Set<uint32_t>(hasSetter, &handler); 154 if (!hasSetter) { 155 KindBit::Set<uint32_t>(HandlerKind::FIELD, &handler); 156 } 157 if (op.IsInlinedProps()) { 158 InlinedPropsBit::Set<uint32_t>(true, &handler); 159 uint32_t index = 0; 160 if (!hasSetter) { 161 JSHandle<JSObject> receiver = JSHandle<JSObject>::Cast(op.GetReceiver()); 162 index = receiver->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex()); 163 } else { 164 JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder()); 165 index = holder->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex()); 166 } 167 OffsetBit::Set<uint32_t>(index, &handler); 168 return JSHandle<JSTaggedValue>(thread, JSTaggedValue(handler)); 169 } 170 ASSERT(op.IsFastMode()); 171 OffsetBit::Set<uint32_t>(op.GetIndex(), &handler); 172 return JSHandle<JSTaggedValue>(thread, JSTaggedValue(handler)); 173 } 174 StoreElement(const JSThread * thread,JSHandle<JSTaggedValue> receiver)175 static inline JSHandle<JSTaggedValue> StoreElement(const JSThread *thread, 176 JSHandle<JSTaggedValue> receiver) 177 { 178 uint32_t handler = 0; 179 KindBit::Set<uint32_t>(HandlerKind::ELEMENT, &handler); 180 181 if (receiver->IsJSArray()) { 182 IsJSArrayBit::Set<uint32_t>(true, &handler); 183 } 184 return JSHandle<JSTaggedValue>(thread, JSTaggedValue(handler)); 185 } 186 }; 187 188 class TransitionHandler : public TaggedObject { 189 public: Cast(TaggedObject * object)190 static TransitionHandler *Cast(TaggedObject *object) 191 { 192 ASSERT(JSTaggedValue(object).IsTransitionHandler()); 193 return static_cast<TransitionHandler *>(object); 194 } 195 StoreTransition(const JSThread * thread,const ObjectOperator & op)196 static inline JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op) 197 { 198 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 199 JSHandle<TransitionHandler> handler = factory->NewTransitionHandler(); 200 JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op); 201 handler->SetHandlerInfo(thread, handlerInfo); 202 auto hclass = JSObject::Cast(op.GetReceiver()->GetTaggedObject())->GetJSHClass(); 203 handler->SetTransitionHClass(thread, JSTaggedValue(hclass)); 204 return JSHandle<JSTaggedValue>::Cast(handler); 205 } 206 207 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 208 209 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET) 210 211 ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, SIZE) 212 213 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) 214 DECL_DUMP() 215 }; 216 217 class PrototypeHandler : public TaggedObject { 218 public: Cast(TaggedObject * object)219 static PrototypeHandler *Cast(TaggedObject *object) 220 { 221 ASSERT(JSTaggedValue(object).IsPrototypeHandler()); 222 return static_cast<PrototypeHandler *>(object); 223 } 224 LoadPrototype(const JSThread * thread,const ObjectOperator & op,const JSHandle<JSHClass> & hclass)225 static inline JSHandle<JSTaggedValue> LoadPrototype(const JSThread *thread, const ObjectOperator &op, 226 const JSHandle<JSHClass> &hclass) 227 { 228 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 229 JSHandle<JSTaggedValue> handlerInfo = LoadHandler::LoadProperty(thread, op); 230 JSHandle<PrototypeHandler> handler = factory->NewPrototypeHandler(); 231 handler->SetHandlerInfo(thread, handlerInfo); 232 if (op.IsFound()) { 233 handler->SetHolder(thread, op.GetHolder()); 234 } 235 auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); 236 handler->SetProtoCell(thread, result); 237 return JSHandle<JSTaggedValue>::Cast(handler); 238 } StorePrototype(const JSThread * thread,const ObjectOperator & op,const JSHandle<JSHClass> & hclass)239 static inline JSHandle<JSTaggedValue> StorePrototype(const JSThread *thread, const ObjectOperator &op, 240 const JSHandle<JSHClass> &hclass) 241 { 242 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 243 JSHandle<PrototypeHandler> handler = factory->NewPrototypeHandler(); 244 JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op); 245 handler->SetHandlerInfo(thread, handlerInfo); 246 handler->SetHolder(thread, op.GetHolder()); 247 auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); 248 handler->SetProtoCell(thread, result); 249 return JSHandle<JSTaggedValue>::Cast(handler); 250 } 251 252 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 253 254 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET) 255 256 ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET) 257 258 ACCESSORS(Holder, HOLDER_OFFSET, SIZE) 259 260 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) 261 DECL_DUMP() 262 }; 263 264 class TransWithProtoHandler : public TaggedObject { 265 public: Cast(TaggedObject * object)266 static TransWithProtoHandler *Cast(TaggedObject *object) 267 { 268 ASSERT(JSTaggedValue(object).IsTransWithProtoHandler()); 269 return static_cast<TransWithProtoHandler *>(object); 270 } 271 StoreTransition(const JSThread * thread,const ObjectOperator & op,const JSHandle<JSHClass> & hclass)272 static inline JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op, 273 const JSHandle<JSHClass> &hclass) 274 { 275 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 276 JSHandle<TransWithProtoHandler> handler = factory->NewTransWithProtoHandler(); 277 JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op); 278 handler->SetHandlerInfo(thread, handlerInfo); 279 auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); 280 handler->SetProtoCell(thread, result); 281 handler->SetTransitionHClass(thread, hclass.GetTaggedValue()); 282 283 return JSHandle<JSTaggedValue>::Cast(handler); 284 } 285 286 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 287 288 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET) 289 290 ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, PROTO_CELL_OFFSET) 291 292 ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, SIZE) 293 294 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) 295 DECL_DUMP() 296 }; 297 298 class StoreTSHandler : public TaggedObject { 299 public: Cast(TaggedObject * object)300 static StoreTSHandler *Cast(TaggedObject *object) 301 { 302 ASSERT(JSTaggedValue(object).IsStoreTSHandler()); 303 return static_cast<StoreTSHandler *>(object); 304 } 305 StoreAOT(const JSThread * thread,const ObjectOperator & op,const JSHandle<JSHClass> & hclass)306 static inline JSHandle<JSTaggedValue> StoreAOT(const JSThread *thread, const ObjectOperator &op, 307 const JSHandle<JSHClass> &hclass) 308 { 309 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 310 JSHandle<StoreTSHandler> handler = factory->NewStoreTSHandler(); 311 JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op); 312 handler->SetHandlerInfo(thread, handlerInfo); 313 handler->SetHolder(thread, op.GetHolder()); 314 auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); 315 handler->SetProtoCell(thread, result); 316 return JSHandle<JSTaggedValue>::Cast(handler); 317 } 318 319 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 320 321 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET) 322 323 ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET) 324 325 ACCESSORS(Holder, HOLDER_OFFSET, SIZE) 326 327 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) 328 DECL_DUMP() 329 }; 330 } // namespace panda::ecmascript 331 #endif // ECMASCRIPT_IC_IC_HANDLER_H 332