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