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