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