• 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_OBJECT_OPERATOR_H
17 #define ECMASCRIPT_OBJECT_OPERATOR_H
18 
19 #include "ecmascript/js_handle.h"
20 #include "ecmascript/property_attributes.h"
21 
22 #include "libpandabase/utils/bit_field.h"
23 
24 namespace panda::ecmascript {
25 class PropertyDescriptor;
26 class JSObject;
27 
28 enum class OperatorType : uint8_t {
29     PROTOTYPE_CHAIN,
30     OWN,
31 };
32 
33 class ObjectOperator final {
34 public:
35     ObjectOperator() = default;
36 
37     ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &key,
38                    OperatorType type = OperatorType::PROTOTYPE_CHAIN);
39 
40     ObjectOperator(JSThread *thread, const JSHandle<JSObject> &holder, const JSHandle<JSTaggedValue> &key,
41                    OperatorType type = OperatorType::PROTOTYPE_CHAIN);
42 
43     ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder, const JSHandle<JSTaggedValue> &key,
44                    OperatorType type = OperatorType::PROTOTYPE_CHAIN);
45 
46     ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder,
47                    const JSHandle<JSTaggedValue> &receiver, const JSHandle<JSTaggedValue> &key,
48                    OperatorType type = OperatorType::PROTOTYPE_CHAIN);
49 
50     ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder, uint32_t index,
51                    OperatorType type = OperatorType::PROTOTYPE_CHAIN);
52     // op for fast path, name can only string and symbol, and can't be number.
53     ObjectOperator(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name,
54                    OperatorType type = OperatorType::PROTOTYPE_CHAIN);
55     // op for fast add
56     ObjectOperator(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name,
57                    const PropertyAttributes &attr);
58 
59     static void FastAdd(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name,
60                         const JSHandle<JSTaggedValue> &value, const PropertyAttributes &attr);
61 
62     NO_COPY_SEMANTIC(ObjectOperator);
63     DEFAULT_NOEXCEPT_MOVE_SEMANTIC(ObjectOperator);
64     ~ObjectOperator() = default;
65 
66     /**
67      * Create ObjectOperator instance by new operator is forbidden, for the member holder is a JSHandle type. it must
68      * be created and destroyed on stack
69      */
70     void *operator new([[maybe_unused]] size_t t) = delete;
71     void operator delete([[maybe_unused]] void *ptr) = delete;
72 
IsFound()73     inline bool IsFound() const
74     {
75         return index_ != NOT_FOUND_INDEX;
76     }
77 
IsFastMode()78     inline bool IsFastMode() const
79     {
80         return IsFastModeField::Get(metaData_);
81     }
82 
SetFastMode(bool flag)83     inline void SetFastMode(bool flag)
84     {
85         IsFastModeField::Set(flag, &metaData_);
86     }
87 
IsElement()88     inline bool IsElement() const
89     {
90         return key_.IsEmpty();
91     }
92 
IsOnPrototype()93     inline bool IsOnPrototype() const
94     {
95         return IsOnPrototypeField::Get(metaData_);
96     }
97 
SetIsOnPrototype(bool flag)98     inline void SetIsOnPrototype(bool flag)
99     {
100         IsOnPrototypeField::Set(flag, &metaData_);
101     }
102 
HasReceiver()103     inline bool HasReceiver() const
104     {
105         return HasReceiverField::Get(metaData_);
106     }
107 
SetHasReceiver(bool flag)108     inline void SetHasReceiver(bool flag)
109     {
110         HasReceiverField::Set(flag, &metaData_);
111     }
112 
IsTransition()113     inline bool IsTransition() const
114     {
115         return IsTransitionField::Get(metaData_);
116     }
117 
SetIsTransition(bool flag)118     inline void SetIsTransition(bool flag)
119     {
120         IsTransitionField::Set(flag, &metaData_);
121     }
122 
IsTSHClass()123     inline bool IsTSHClass() const
124     {
125         return IsTSHClassField::Get(metaData_);
126     }
127 
SetIsTSHClass(bool flag)128     inline void SetIsTSHClass(bool flag)
129     {
130         IsTSHClassField::Set(flag, &metaData_);
131     }
132 
GetAttr()133     inline PropertyAttributes GetAttr() const
134     {
135         return attributes_;
136     }
137 
SetAttr(uint32_t attr)138     inline void SetAttr(uint32_t attr)
139     {
140         attributes_ = PropertyAttributes(attr);
141     }
142 
SetAttr(const PropertyAttributes & attr)143     inline void SetAttr(const PropertyAttributes &attr)
144     {
145         attributes_ = PropertyAttributes(attr);
146     }
147 
IsPrimitiveAttr()148     inline bool IsPrimitiveAttr() const
149     {
150         return !attributes_.GetValue();
151     }
152 
IsWritable()153     inline bool IsWritable() const
154     {
155         return GetAttr().IsWritable();
156     }
157 
IsEnumerable()158     inline bool IsEnumerable() const
159     {
160         return GetAttr().IsEnumerable();
161     }
162 
IsConfigurable()163     inline bool IsConfigurable() const
164     {
165         return GetAttr().IsConfigurable();
166     }
167 
IsAccessorDescriptor()168     inline bool IsAccessorDescriptor() const
169     {
170         return GetAttr().IsAccessor();
171     }
172 
IsInlinedProps()173     inline bool IsInlinedProps() const
174     {
175         return GetAttr().IsInlinedProps();
176     }
177 
SetIsInlinedProps(bool flag)178     inline void SetIsInlinedProps(bool flag)
179     {
180         attributes_.SetIsInlinedProps(flag);
181     }
182 
GetRepresentation()183     inline Representation GetRepresentation() const
184     {
185         return GetAttr().GetRepresentation();
186     }
187 
GetValue()188     inline JSTaggedValue GetValue() const
189     {
190         if (value_.IsEmpty()) {
191             return JSTaggedValue::Undefined();
192         }
193         return value_.GetTaggedValue();
194     }
195 
196     JSHandle<JSTaggedValue> FastGetValue();
SetValue(JSTaggedValue value)197     inline void SetValue(JSTaggedValue value)
198     {
199         if (value_.IsEmpty()) {
200             value_ = JSMutableHandle<JSTaggedValue>(thread_, value);
201         }
202         value_.Update(value);
203     }
204 
SetIndex(uint32_t index)205     inline void SetIndex(uint32_t index)
206     {
207         index_ = index;
208     }
209 
GetIndex()210     inline uint32_t GetIndex() const
211     {
212         return index_;
213     }
214 
HasHolder()215     inline bool HasHolder() const
216     {
217         return !holder_.IsEmpty();
218     }
219 
GetHolder()220     inline JSHandle<JSTaggedValue> GetHolder() const
221     {
222         return holder_;
223     }
224 
GetReceiver()225     inline JSHandle<JSTaggedValue> GetReceiver() const
226     {
227         return receiver_;
228     }
229 
GetKey()230     inline JSHandle<JSTaggedValue> GetKey() const
231     {
232         if (key_.IsEmpty()) {
233             return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
234         }
235         return key_;
236     }
237 
GetElementIndex()238     inline uint32_t GetElementIndex() const
239     {
240         return elementIndex_;
241     }
242 
GetThread()243     inline JSThread *GetThread() const
244     {
245         return thread_;
246     }
247 
248     void ToPropertyDescriptor(PropertyDescriptor &desc) const;
249     void LookupProperty();
250     void GlobalLookupProperty();
ReLookupPropertyInReceiver()251     inline void ReLookupPropertyInReceiver()
252     {
253         ResetState();
254         return LookupPropertyInlinedProps(JSHandle<JSObject>(receiver_));
255     }
SetAsDefaultAttr()256     inline void SetAsDefaultAttr()
257     {
258         SetFound(NOT_FOUND_INDEX, JSTaggedValue::Undefined(), PropertyAttributes::GetDefaultAttributes(), false, false);
259     }
260     JSTaggedValue ConvertOrTransitionWithRep(const JSHandle<JSObject> &receiver,
261         const JSHandle<JSTaggedValue> &value, PropertyAttributes &attr, bool &needBarrier);
262     bool UpdateDataValue(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
263                          bool isInternalAccessor, bool mayThrow = false);
WriteDataPropertyInHolder(const PropertyDescriptor & desc)264     bool WriteDataPropertyInHolder(const PropertyDescriptor &desc)
265     {
266         JSHandle<JSObject> receiver(holder_);
267         return WriteDataProperty(receiver, desc);
268     }
269     bool WriteDataProperty(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc);
270     bool AddProperty(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value, PropertyAttributes attr);
AddPropertyInHolder(const JSHandle<JSTaggedValue> & value,PropertyAttributes attr)271     inline bool AddPropertyInHolder(const JSHandle<JSTaggedValue> &value, PropertyAttributes attr)
272     {
273         JSHandle<JSObject> obj(holder_);
274         return AddProperty(obj, value, attr);
275     }
276     void DeletePropertyInHolder();
277     static constexpr uint32_t NOT_FOUND_INDEX = std::numeric_limits<uint32_t>::max();
278     static JSTaggedValue ToHolder(const JSHandle<JSTaggedValue> &holder);
279     void AddPropertyInternal(const JSHandle<JSTaggedValue> &value);
280     void DefineSetter(const JSHandle<JSTaggedValue> &value);
281     void DefineGetter(const JSHandle<JSTaggedValue> &value);
282 
283 private:
284     static constexpr uint64_t ATTR_LENGTH = 5;
285     static constexpr uint64_t INDEX_LENGTH = 32;
286 
287     using IsFastModeField = BitField<bool, 0, 1>;
288     using IsOnPrototypeField = IsFastModeField::NextFlag;  // 1: on prototype
289     using HasReceiverField = IsOnPrototypeField::NextFlag;
290     using IsTransitionField = HasReceiverField::NextFlag;
291     using IsTSHClassField = IsTransitionField::NextFlag;
292 
293     void UpdateHolder();
294     void UpdateIsTSHClass();
295     void StartLookUp(OperatorType type);
296     void StartGlobalLookUp(OperatorType type);
297     void HandleKey(const JSHandle<JSTaggedValue> &key);
298     uint32_t ComputeElementCapacity(uint32_t oldCapacity);
299     void SetFound(uint32_t index, JSTaggedValue value, uint32_t attr, bool mode, bool transition = false);
300     void UpdateFound(uint32_t index, uint32_t attr, bool mode, bool transition);
301     void ResetState();
302     void ResetStateForAddProperty();
LookupPropertyInHolder()303     inline void LookupPropertyInHolder()
304     {
305         JSHandle<JSObject> obj(holder_);
306         LookupPropertyInlinedProps(obj);
307     }
GlobalLookupPropertyInHolder()308     inline void GlobalLookupPropertyInHolder()
309     {
310         JSHandle<JSObject> obj(holder_);
311         LookupGlobal(obj);
312     }
313     void LookupGlobal(const JSHandle<JSObject> &obj);
314     void LookupPropertyInlinedProps(const JSHandle<JSObject> &obj);
315     void LookupElementInlinedProps(const JSHandle<JSObject> &obj);
316     void WriteElement(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc);
317     void WriteElement(const JSHandle<JSObject> &receiver, JSTaggedValue value) const;
318     void DeleteElementInHolder() const;
319     bool UpdateValueAndDetails(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
320                                PropertyAttributes attr, bool attrChanged);
321     void TransitionForAttributeChanged(const JSHandle<JSObject> &receiver, PropertyAttributes attr);
322     JSThread *thread_{nullptr};
323     JSMutableHandle<JSTaggedValue> value_{};
324     JSMutableHandle<JSTaggedValue> holder_{};
325     JSMutableHandle<JSTaggedValue> receiver_{};
326     JSHandle<JSTaggedValue> key_{};
327     uint32_t elementIndex_{NOT_FOUND_INDEX};
328     uint32_t index_{NOT_FOUND_INDEX};
329     PropertyAttributes attributes_;
330     uint32_t metaData_{0};
331     int receiverHoleEntry_{-1};
332 };
333 }  // namespace panda::ecmascript
334 #endif  // ECMASCRIPT_OBJECT_OPERATOR_H
335