• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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