• 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     explicit ObjectOperator() = default;
36 
37     explicit ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &key,
38                             OperatorType type = OperatorType::PROTOTYPE_CHAIN);
39 
40     explicit ObjectOperator(JSThread *thread, const JSHandle<JSObject> &holder, const JSHandle<JSTaggedValue> &key,
41                             OperatorType type = OperatorType::PROTOTYPE_CHAIN);
42 
43     explicit ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder, const JSHandle<JSTaggedValue> &key,
44                             OperatorType type = OperatorType::PROTOTYPE_CHAIN);
45 
46     explicit ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder,
47                             const JSHandle<JSTaggedValue> &receiver, const JSHandle<JSTaggedValue> &key,
48                             OperatorType type = OperatorType::PROTOTYPE_CHAIN);
49 
50     explicit 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     explicit ObjectOperator(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name,
54                             OperatorType type = OperatorType::PROTOTYPE_CHAIN);
55     // op for fast add
56     explicit 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 
GetValue()183     inline JSTaggedValue GetValue() const
184     {
185         if (value_.IsEmpty()) {
186             return JSTaggedValue::Undefined();
187         }
188         return value_.GetTaggedValue();
189     }
190 
191     JSHandle<JSTaggedValue> FastGetValue();
SetValue(JSTaggedValue value)192     inline void SetValue(JSTaggedValue value)
193     {
194         if (value_.IsEmpty()) {
195             value_ = JSMutableHandle<JSTaggedValue>(thread_, value);
196         }
197         value_.Update(value);
198     }
199 
SetIndex(uint32_t index)200     inline void SetIndex(uint32_t index)
201     {
202         index_ = index;
203     }
204 
GetIndex()205     inline uint32_t GetIndex() const
206     {
207         return index_;
208     }
209 
HasHolder()210     inline bool HasHolder() const
211     {
212         return !holder_.IsEmpty();
213     }
214 
GetHolder()215     inline JSHandle<JSTaggedValue> GetHolder() const
216     {
217         return holder_;
218     }
219 
GetReceiver()220     inline JSHandle<JSTaggedValue> GetReceiver() const
221     {
222         return receiver_;
223     }
224 
GetKey()225     inline JSHandle<JSTaggedValue> GetKey() const
226     {
227         if (key_.IsEmpty()) {
228             return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
229         }
230         return key_;
231     }
232 
GetElementIndex()233     inline uint32_t GetElementIndex() const
234     {
235         return elementIndex_;
236     }
237 
GetThread()238     inline JSThread *GetThread() const
239     {
240         return thread_;
241     }
242 
243     void ToPropertyDescriptor(PropertyDescriptor &desc) const;
244     void LookupProperty();
245     void GlobalLookupProperty();
ReLookupPropertyInReceiver()246     inline void ReLookupPropertyInReceiver()
247     {
248         ResetState();
249         return LookupPropertyInlinedProps(JSHandle<JSObject>(receiver_));
250     }
SetAsDefaultAttr()251     inline void SetAsDefaultAttr()
252     {
253         SetFound(NOT_FOUND_INDEX, JSTaggedValue::Undefined(), PropertyAttributes::GetDefaultAttributes(), false, false);
254     }
255     bool UpdateDataValue(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
256                          bool isInternalAccessor, bool mayThrow = false);
WriteDataPropertyInHolder(const PropertyDescriptor & desc)257     bool WriteDataPropertyInHolder(const PropertyDescriptor &desc)
258     {
259         JSHandle<JSObject> receiver(holder_);
260         return WriteDataProperty(receiver, desc);
261     }
262     bool WriteDataProperty(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc);
263     bool AddProperty(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value, PropertyAttributes attr);
AddPropertyInHolder(const JSHandle<JSTaggedValue> & value,PropertyAttributes attr)264     inline bool AddPropertyInHolder(const JSHandle<JSTaggedValue> &value, PropertyAttributes attr)
265     {
266         JSHandle<JSObject> obj(holder_);
267         return AddProperty(obj, value, attr);
268     }
269     void DeletePropertyInHolder();
270     static constexpr uint32_t NOT_FOUND_INDEX = std::numeric_limits<uint32_t>::max();
271     static JSTaggedValue ToHolder(const JSHandle<JSTaggedValue> &holder);
272     void AddPropertyInternal(const JSHandle<JSTaggedValue> &value);
273     void DefineSetter(const JSHandle<JSTaggedValue> &value);
274     void DefineGetter(const JSHandle<JSTaggedValue> &value);
275 
276 private:
277     static constexpr uint64_t ATTR_LENGTH = 5;
278     static constexpr uint64_t INDEX_LENGTH = 32;
279 
280     using IsFastModeField = BitField<bool, 0, 1>;
281     using IsOnPrototypeField = IsFastModeField::NextFlag;  // 1: on prototype
282     using HasReceiverField = IsOnPrototypeField::NextFlag;
283     using IsTransitionField = HasReceiverField::NextFlag;
284     using IsTSHClassField = IsTransitionField::NextFlag;
285 
286     void UpdateHolder();
287     void UpdateIsTSHClass();
288     void StartLookUp(OperatorType type);
289     void StartGlobalLookUp(OperatorType type);
290     void HandleKey(const JSHandle<JSTaggedValue> &key);
291     uint32_t ComputeElementCapacity(uint32_t oldCapacity);
292     void SetFound(uint32_t index, JSTaggedValue value, uint32_t attr, bool mode, bool transition = false);
293     void UpdateFound(uint32_t index, uint32_t attr, bool mode, bool transition);
294     void ResetState();
295     void ResetStateForAddProperty();
LookupPropertyInHolder()296     inline void LookupPropertyInHolder()
297     {
298         JSHandle<JSObject> obj(holder_);
299         LookupPropertyInlinedProps(obj);
300     }
GlobalLookupPropertyInHolder()301     inline void GlobalLookupPropertyInHolder()
302     {
303         JSHandle<JSObject> obj(holder_);
304         LookupGlobal(obj);
305     }
306     void LookupGlobal(const JSHandle<JSObject> &obj);
307     void LookupPropertyInlinedProps(const JSHandle<JSObject> &obj);
308     void LookupElementInlinedProps(const JSHandle<JSObject> &obj);
309     void WriteElement(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc);
310     void WriteElement(const JSHandle<JSObject> &receiver, JSTaggedValue value) const;
311     void DeleteElementInHolder() const;
312     bool UpdateValueAndDetails(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
313                                PropertyAttributes attr, bool attrChanged);
314     void TransitionForAttributeChanged(const JSHandle<JSObject> &receiver, PropertyAttributes attr);
315     JSThread *thread_{nullptr};
316     JSMutableHandle<JSTaggedValue> value_{};
317     JSMutableHandle<JSTaggedValue> holder_{};
318     JSMutableHandle<JSTaggedValue> receiver_{};
319     JSHandle<JSTaggedValue> key_{};
320     uint32_t elementIndex_{NOT_FOUND_INDEX};
321     uint32_t index_{NOT_FOUND_INDEX};
322     PropertyAttributes attributes_;
323     uint32_t metaData_{0};
324     int receiverHoleEntry_{-1};
325 };
326 }  // namespace panda::ecmascript
327 #endif  // ECMASCRIPT_OBJECT_OPERATOR_H
328