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::OFFSET_BITFIELD_NUM>; // [7, 17) 61 using RepresentationBit = OffsetBit::NextField<Representation, PropertyAttributes::REPRESENTATION_NUM>; // [17, 19) 62 using AttrIndexBit = RepresentationBit::NextField<uint32_t, PropertyAttributes::OFFSET_BITFIELD_NUM>; // [19, 29) 63 using IsOnHeapBit = AttrIndexBit::NextFlag; // [29, 30) 64 using NeedSkipInPGODumpBit = IsOnHeapBit::NextFlag; // [30, 31) 65 static_assert(NeedSkipInPGODumpBit::END_BIT <= MAX_BIT_SIZE, "load handler overflow"); 66 67 // For Store 68 using SWholeKindBit = KindBit; 69 using SKindBit = BitField<StoreHandlerKind, 0, STORE_KIND_BIT_LENGTH>; // [0, 2) 70 static_assert(SKindBit::START_BIT == KindBit::START_BIT); 71 using SSharedBit = SKindBit::NextFlag; // [2, 4) 72 static_assert((SKindBit::SIZE + SSharedBit::SIZE) <= KindBit::SIZE); // reuse: [0, 4) bits 73 // shared with Load bits: [4, 30) 74 using SOutOfBoundsBit = IsOnHeapBit::NextFlag; // reuse: [30, 31) bit 75 using SFieldTypeBit = SOutOfBoundsBit::NextField<SharedFieldType, PropertyAttributes::FIELD_TYPE_NUM>; // [31, 39) 76 static_assert(SFieldTypeBit::END_BIT <= MAX_BIT_SIZE, "store handler overflow"); 77 using Type = uint64_t; 78 static_assert(sizeof(Type) <= JSTaggedValue::TaggedTypeSize()); 79 80 HandlerBase() = default; 81 virtual ~HandlerBase() = default; 82 IsAccessor(Type handler)83 static inline bool IsAccessor(Type handler) 84 { 85 return AccessorBit::Get(handler); 86 } 87 GetFieldType(Type handler)88 static inline SharedFieldType GetFieldType(Type handler) 89 { 90 return static_cast<SharedFieldType>(SFieldTypeBit::Get(handler)); 91 } 92 IsNonExist(Type handler)93 static inline bool IsNonExist(Type handler) 94 { 95 return GetKind(handler) == HandlerKind::NON_EXIST; 96 } 97 IsField(Type handler)98 static inline bool IsField(Type handler) 99 { 100 return GetKind(handler) == HandlerKind::FIELD; 101 } 102 IsNonSharedStoreField(Type handler)103 static inline bool IsNonSharedStoreField(Type handler) 104 { 105 return static_cast<StoreHandlerKind>(GetKind(handler)) == StoreHandlerKind::S_FIELD; 106 } 107 IsStoreShared(Type handler)108 static inline bool IsStoreShared(Type handler) 109 { 110 return SSharedBit::Get(handler); 111 } 112 ClearSharedStoreKind(Type & handler)113 static inline void ClearSharedStoreKind(Type &handler) 114 { 115 SSharedBit::Set<Type>(false, &handler); 116 } 117 IsStoreOutOfBounds(Type handler)118 static inline bool IsStoreOutOfBounds(Type handler) 119 { 120 return SOutOfBoundsBit::Get(handler); 121 } 122 ClearStoreOutOfBounds(Type & handler)123 static inline void ClearStoreOutOfBounds(Type &handler) 124 { 125 SOutOfBoundsBit::Set<Type>(false, &handler); 126 } 127 IsString(Type handler)128 static inline bool IsString(Type handler) 129 { 130 return GetKind(handler) == HandlerKind::STRING; 131 } 132 IsNumber(Type handler)133 static inline bool IsNumber(Type handler) 134 { 135 return GetKind(handler) == HandlerKind::NUMBER; 136 } 137 IsStringLength(Type handler)138 static inline bool IsStringLength(Type handler) 139 { 140 return GetKind(handler) == HandlerKind::STRING_LENGTH; 141 } 142 IsElement(Type handler)143 static inline bool IsElement(Type handler) 144 { 145 return IsNormalElement(handler) || IsStringElement(handler) || IsTypedArrayElement(handler); 146 } 147 IsNormalElement(Type handler)148 static inline bool IsNormalElement(Type handler) 149 { 150 return GetKind(handler) == HandlerKind::ELEMENT; 151 } 152 IsStringElement(Type handler)153 static inline bool IsStringElement(Type handler) 154 { 155 return GetKind(handler) == HandlerKind::STRING; 156 } 157 IsTypedArrayElement(Type handler)158 static inline bool IsTypedArrayElement(Type handler) 159 { 160 return GetKind(handler) == HandlerKind::TYPED_ARRAY; 161 } 162 IsDictionary(Type handler)163 static inline bool IsDictionary(Type handler) 164 { 165 return GetKind(handler) == HandlerKind::DICTIONARY; 166 } 167 IsInlinedProps(Type handler)168 static inline bool IsInlinedProps(Type handler) 169 { 170 return InlinedPropsBit::Get(handler); 171 } 172 GetKind(Type handler)173 static inline HandlerKind GetKind(Type handler) 174 { 175 return KindBit::Get(handler); 176 } 177 IsJSArray(Type handler)178 static inline bool IsJSArray(Type handler) 179 { 180 return IsJSArrayBit::Get(handler); 181 } 182 NeedSkipInPGODump(Type handler)183 static inline bool NeedSkipInPGODump(Type handler) 184 { 185 return NeedSkipInPGODumpBit::Get(handler); 186 } 187 GetOffset(Type handler)188 static inline int GetOffset(Type handler) 189 { 190 return OffsetBit::Get(handler); 191 } 192 IsOnHeap(Type handler)193 static inline bool IsOnHeap(Type handler) 194 { 195 return IsOnHeapBit::Get(handler); 196 } 197 }; 198 199 class LoadHandler final : public HandlerBase { 200 public: LoadProperty(const JSThread * thread,const ObjectOperator & op)201 static inline JSHandle<JSTaggedValue> LoadProperty(const JSThread *thread, const ObjectOperator &op) 202 { 203 uint64_t handler = 0; 204 ASSERT(!op.IsElement()); 205 if (!op.IsFound()) { 206 KindBit::Set<uint64_t>(HandlerKind::NON_EXIST, &handler); 207 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 208 } 209 ASSERT(op.IsFastMode()); 210 211 JSTaggedValue val = op.GetValue(); 212 if (val.IsPropertyBox()) { 213 return JSHandle<JSTaggedValue>(thread, val); 214 } 215 bool hasAccessor = op.IsAccessorDescriptor(); 216 AccessorBit::Set<uint64_t>(hasAccessor, &handler); 217 218 if (!hasAccessor) { 219 if (op.GetReceiver()->IsString()) { 220 JSTaggedValue lenKey = thread->GlobalConstants()->GetLengthString(); 221 EcmaString *proKey = nullptr; 222 if (op.GetKey()->IsString()) { 223 proKey = EcmaString::Cast(op.GetKey()->GetTaggedObject()); 224 } 225 if (EcmaStringAccessor::StringsAreEqual(proKey, EcmaString::Cast(lenKey.GetTaggedObject()))) { 226 KindBit::Set<uint64_t>(HandlerKind::STRING_LENGTH, &handler); 227 } else { 228 KindBit::Set<uint64_t>(HandlerKind::STRING, &handler); 229 } 230 } else if (op.GetReceiver()->IsNumber()) { 231 KindBit::Set<uint64_t>(HandlerKind::NUMBER, &handler); 232 } else { 233 KindBit::Set<uint64_t>(HandlerKind::FIELD, &handler); 234 } 235 } 236 237 if (op.IsInlinedProps()) { 238 InlinedPropsBit::Set<uint64_t>(true, &handler); 239 JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder()); 240 auto index = holder->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex()); 241 OffsetBit::Set<uint64_t>(index, &handler); 242 AttrIndexBit::Set<uint64_t>(op.GetIndex(), &handler); 243 RepresentationBit::Set<uint64_t>(op.GetRepresentation(), &handler); 244 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 245 } 246 if (op.IsFastMode()) { 247 JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder()); 248 uint32_t inlinePropNum = holder->GetJSHClass()->GetInlinedProperties(); 249 AttrIndexBit::Set<uint64_t>(op.GetIndex() + inlinePropNum, &handler); 250 OffsetBit::Set<uint64_t>(op.GetIndex(), &handler); 251 RepresentationBit::Set<uint64_t>(Representation::TAGGED, &handler); 252 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 253 } 254 LOG_ECMA(FATAL) << "this branch is unreachable"; 255 UNREACHABLE(); 256 } 257 LoadElement(const JSThread * thread,const ObjectOperator & op)258 static inline JSHandle<JSTaggedValue> LoadElement(const JSThread *thread, const ObjectOperator &op) 259 { 260 uint64_t handler = 0; 261 KindBit::Set<uint64_t>(HandlerKind::ELEMENT, &handler); 262 263 // To avoid logical errors and Deopt, temporarily skipping PGO Profiling. 264 // logical errors: 265 // When accessing an element of an object, AOT does not have a chain-climbing operation, 266 // so if the element is on a prototype, it will not be able to get the correct element. 267 // deopt: 268 // Currently there is no way to save the type of the key in pgo file, even if the type of the key 269 // is string, it will be treated as a number type by the AOT, leading to deopt at runtime. 270 if (op.GetReceiver() != op.GetHolder() || 271 op.KeyFromStringType()) { 272 NeedSkipInPGODumpBit::Set<uint64_t>(true, &handler); 273 } 274 275 if (op.GetReceiver()->IsJSArray()) { 276 IsJSArrayBit::Set<uint64_t>(true, &handler); 277 } 278 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 279 } 280 LoadStringElement(const JSThread * thread)281 static inline JSHandle<JSTaggedValue> LoadStringElement(const JSThread *thread) 282 { 283 uint64_t handler = 0; 284 KindBit::Set<uint64_t>(HandlerKind::STRING, &handler); 285 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 286 } 287 LoadTypedArrayElement(const JSThread * thread,JSHandle<JSTypedArray> typedArray)288 static inline JSHandle<JSTaggedValue> LoadTypedArrayElement(const JSThread *thread, 289 JSHandle<JSTypedArray> typedArray) 290 { 291 uint64_t handler = 0; 292 KindBit::Set<uint64_t>(HandlerKind::TYPED_ARRAY, &handler); 293 IsOnHeapBit::Set<uint64_t>(JSHandle<TaggedObject>(typedArray)->GetClass()->IsOnHeapFromBitField(), &handler); 294 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 295 } 296 }; 297 298 class StoreHandler final : public HandlerBase { 299 public: StoreProperty(const JSThread * thread,const ObjectOperator & op)300 static inline JSHandle<JSTaggedValue> StoreProperty(const JSThread *thread, const ObjectOperator &op) 301 { 302 uint64_t handler = 0; 303 JSHandle<JSObject> receiver = JSHandle<JSObject>::Cast(op.GetReceiver()); 304 SSharedBit::Set<uint64_t>(op.GetReceiver()->IsJSShared(), &handler); 305 TaggedArray *array = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject()); 306 if (!array->IsDictionaryMode()) { 307 SFieldTypeBit::Set<uint64_t>(op.GetAttr().GetSharedFieldType(), &handler); 308 } else { 309 SFieldTypeBit::Set<uint64_t>(op.GetAttr().GetDictSharedFieldType(), &handler); 310 } 311 if (op.IsElement()) { 312 SOutOfBoundsBit::Set<uint64_t>(op.GetElementOutOfBounds(), &handler); 313 return StoreElement(thread, op.GetReceiver(), handler); 314 } 315 JSTaggedValue val = op.GetValue(); 316 if (val.IsPropertyBox()) { 317 return JSHandle<JSTaggedValue>(thread, val); 318 } 319 bool hasSetter = op.IsAccessorDescriptor(); 320 AccessorBit::Set<uint64_t>(hasSetter, &handler); 321 if (!hasSetter) { 322 SKindBit::Set<uint64_t>(StoreHandlerKind::S_FIELD, &handler); 323 } 324 if (op.IsInlinedProps()) { 325 InlinedPropsBit::Set<uint64_t>(true, &handler); 326 uint32_t index = 0; 327 if (!hasSetter) { 328 index = receiver->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex()); 329 } else { 330 JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder()); 331 index = holder->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex()); 332 } 333 AttrIndexBit::Set<uint64_t>(op.GetIndex(), &handler); 334 OffsetBit::Set<uint64_t>(index, &handler); 335 RepresentationBit::Set(op.GetRepresentation(), &handler); 336 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 337 } 338 ASSERT(op.IsFastMode()); 339 uint32_t inlinePropNum = receiver->GetJSHClass()->GetInlinedProperties(); 340 AttrIndexBit::Set<uint64_t>(op.GetIndex() + inlinePropNum, &handler); 341 OffsetBit::Set<uint64_t>(op.GetIndex(), &handler); 342 RepresentationBit::Set(Representation::TAGGED, &handler); 343 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 344 } 345 StoreElement(const JSThread * thread,JSHandle<JSTaggedValue> receiver,uint64_t handler)346 static inline JSHandle<JSTaggedValue> StoreElement(const JSThread *thread, 347 JSHandle<JSTaggedValue> receiver, uint64_t handler) 348 { 349 SKindBit::Set<uint64_t>(StoreHandlerKind::S_ELEMENT, &handler); 350 351 if (receiver->IsJSArray()) { 352 IsJSArrayBit::Set<uint64_t>(true, &handler); 353 } 354 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler)); 355 } 356 }; 357 358 class TransitionHandler : public TaggedObject { 359 public: Cast(TaggedObject * object)360 static TransitionHandler *Cast(TaggedObject *object) 361 { 362 ASSERT(JSTaggedValue(object).IsTransitionHandler()); 363 return static_cast<TransitionHandler *>(object); 364 } 365 StoreTransition(const JSThread * thread,const ObjectOperator & op)366 static inline JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op) 367 { 368 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 369 JSHandle<TransitionHandler> handler = factory->NewTransitionHandler(); 370 JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op); 371 handler->SetHandlerInfo(thread, handlerInfo); 372 auto hclass = JSObject::Cast(op.GetReceiver()->GetTaggedObject())->GetJSHClass(); 373 handler->SetTransitionHClass(thread, JSTaggedValue(hclass)); 374 return JSHandle<JSTaggedValue>::Cast(handler); 375 } 376 377 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 378 379 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET) 380 381 ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, SIZE) 382 383 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) 384 DECL_DUMP() 385 }; 386 387 class PrototypeHandler : public TaggedObject { 388 public: Cast(TaggedObject * object)389 static PrototypeHandler *Cast(TaggedObject *object) 390 { 391 ASSERT(JSTaggedValue(object).IsPrototypeHandler()); 392 return static_cast<PrototypeHandler *>(object); 393 } 394 LoadPrototype(const JSThread * thread,const ObjectOperator & op,const JSHandle<JSHClass> & hclass)395 static inline JSHandle<JSTaggedValue> LoadPrototype(const JSThread *thread, const ObjectOperator &op, 396 const JSHandle<JSHClass> &hclass) 397 { 398 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 399 JSHandle<JSTaggedValue> handlerInfo = LoadHandler::LoadProperty(thread, op); 400 JSHandle<PrototypeHandler> handler = factory->NewPrototypeHandler(); 401 handler->SetHandlerInfo(thread, handlerInfo); 402 if (op.IsFound()) { 403 handler->SetHolder(thread, op.GetHolder()); 404 } 405 if (op.IsAccessorDescriptor()) { 406 JSTaggedValue result = op.GetValue(); 407 if (result.IsPropertyBox()) { 408 result = PropertyBox::Cast(result.GetTaggedObject())->GetValue(); 409 } 410 AccessorData *accessor = AccessorData::Cast(result.GetTaggedObject()); 411 if (!accessor->IsInternal()) { 412 JSTaggedValue getter = accessor->GetGetter(); 413 if (!getter.IsUndefined()) { 414 JSHandle<JSFunction> func(thread, getter); 415 uint32_t methodOffset = Method::Cast(func->GetMethod())->GetMethodId().GetOffset(); 416 handler->SetAccessorMethodId(methodOffset); 417 handler->SetAccessorJSFunction(thread, getter); 418 } 419 } 420 } 421 // ShareToLocal is prohibited 422 if (!hclass->IsJSShared()) { 423 auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); 424 handler->SetProtoCell(thread, result); 425 } 426 return JSHandle<JSTaggedValue>::Cast(handler); 427 } StorePrototype(const JSThread * thread,const ObjectOperator & op,const JSHandle<JSHClass> & hclass)428 static inline JSHandle<JSTaggedValue> StorePrototype(const JSThread *thread, const ObjectOperator &op, 429 const JSHandle<JSHClass> &hclass) 430 { 431 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 432 JSHandle<PrototypeHandler> handler = factory->NewPrototypeHandler(); 433 JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op); 434 handler->SetHandlerInfo(thread, handlerInfo); 435 handler->SetHolder(thread, op.GetHolder()); 436 if (op.IsAccessorDescriptor()) { 437 JSTaggedValue result = op.GetValue(); 438 if (result.IsPropertyBox()) { 439 result = PropertyBox::Cast(result.GetTaggedObject())->GetValue(); 440 } 441 AccessorData *accessor = AccessorData::Cast(result.GetTaggedObject()); 442 if (!accessor->IsInternal() && accessor->HasSetter()) { 443 JSTaggedValue setter = accessor->GetSetter(); 444 JSHandle<JSFunction> func(thread, setter); 445 handler->SetAccessorMethodId( 446 Method::Cast(func->GetMethod())->GetMethodId().GetOffset()); 447 handler->SetAccessorJSFunction(thread, setter); 448 } 449 } 450 // ShareToLocal is prohibited 451 if (!hclass->IsJSShared()) { 452 auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); 453 handler->SetProtoCell(thread, result); 454 } 455 return JSHandle<JSTaggedValue>::Cast(handler); 456 } 457 458 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 459 460 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET) 461 462 ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET) 463 464 ACCESSORS(Holder, HOLDER_OFFSET, ACCESSOR_JSFUNCTION_OFFSET) 465 ACCESSORS(AccessorJSFunction, ACCESSOR_JSFUNCTION_OFFSET, ACCESSOR_METHOD_ID_OFFSET) 466 467 ACCESSORS_PRIMITIVE_FIELD(AccessorMethodId, uint32_t, ACCESSOR_METHOD_ID_OFFSET, LAST_OFFSET) 468 469 DEFINE_ALIGN_SIZE(LAST_OFFSET); 470 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, ACCESSOR_METHOD_ID_OFFSET) 471 DECL_DUMP() 472 }; 473 474 class TransWithProtoHandler : public TaggedObject { 475 public: Cast(TaggedObject * object)476 static TransWithProtoHandler *Cast(TaggedObject *object) 477 { 478 ASSERT(JSTaggedValue(object).IsTransWithProtoHandler()); 479 return static_cast<TransWithProtoHandler *>(object); 480 } 481 StoreTransition(const JSThread * thread,const ObjectOperator & op,const JSHandle<JSHClass> & hclass)482 static inline JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op, 483 const JSHandle<JSHClass> &hclass) 484 { 485 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 486 JSHandle<TransWithProtoHandler> handler = factory->NewTransWithProtoHandler(); 487 JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op); 488 handler->SetHandlerInfo(thread, handlerInfo); 489 auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); 490 handler->SetProtoCell(thread, result); 491 handler->SetTransitionHClass(thread, hclass.GetTaggedValue()); 492 493 return JSHandle<JSTaggedValue>::Cast(handler); 494 } 495 496 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 497 498 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET) 499 500 ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, PROTO_CELL_OFFSET) 501 502 ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, SIZE) 503 504 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) 505 DECL_DUMP() 506 }; 507 508 class StoreTSHandler : public TaggedObject { 509 public: Cast(TaggedObject * object)510 static StoreTSHandler *Cast(TaggedObject *object) 511 { 512 ASSERT(JSTaggedValue(object).IsStoreTSHandler()); 513 return static_cast<StoreTSHandler *>(object); 514 } 515 StoreAOT(const JSThread * thread,const ObjectOperator & op,const JSHandle<JSHClass> & hclass)516 static inline JSHandle<JSTaggedValue> StoreAOT(const JSThread *thread, const ObjectOperator &op, 517 const JSHandle<JSHClass> &hclass) 518 { 519 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 520 JSHandle<StoreTSHandler> handler = factory->NewStoreTSHandler(); 521 JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op); 522 handler->SetHandlerInfo(thread, handlerInfo); 523 handler->SetHolder(thread, op.GetHolder()); 524 auto result = JSHClass::EnableProtoChangeMarker(thread, hclass); 525 handler->SetProtoCell(thread, result); 526 return JSHandle<JSTaggedValue>::Cast(handler); 527 } 528 529 static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize(); 530 531 ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET) 532 533 ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET) 534 535 ACCESSORS(Holder, HOLDER_OFFSET, SIZE) 536 537 DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) 538 DECL_DUMP() 539 }; 540 } // namespace panda::ecmascript 541 #endif // ECMASCRIPT_IC_IC_HANDLER_H 542