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