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