• 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 
GetThroughElement()112     inline bool GetThroughElement() const
113     {
114         uint32_t len = EcmaStringAccessor(holder_->GetTaggedObject()).GetLength();
115         bool flag = elementIndex_ < len;
116         return key_.IsEmpty() && flag;
117     }
118 
GetStringLength()119     inline bool GetStringLength() const
120     {
121         JSTaggedValue lenKey = thread_->GlobalConstants()->GetLengthString();
122         if (GetKey()->IsUndefined() || !GetKey()->IsString()) {
123             return false;
124         }
125         EcmaString *proKey = EcmaString::Cast(GetKey()->GetTaggedObject());
126         return receiver_->IsString() && EcmaStringAccessor::StringsAreEqual(proKey,
127             EcmaString::Cast(lenKey.GetTaggedObject()));
128     }
129 
IsOnPrototype()130     inline bool IsOnPrototype() const
131     {
132         return IsOnPrototypeField::Get(metaData_);
133     }
134 
SetIsOnPrototype(bool flag)135     inline void SetIsOnPrototype(bool flag)
136     {
137         IsOnPrototypeField::Set(flag, &metaData_);
138     }
139 
HasReceiver()140     inline bool HasReceiver() const
141     {
142         return HasReceiverField::Get(metaData_);
143     }
144 
SetHasReceiver(bool flag)145     inline void SetHasReceiver(bool flag)
146     {
147         HasReceiverField::Set(flag, &metaData_);
148     }
149 
IsTransition()150     inline bool IsTransition() const
151     {
152         return IsTransitionField::Get(metaData_);
153     }
154 
SetIsTransition(bool flag)155     inline void SetIsTransition(bool flag)
156     {
157         IsTransitionField::Set(flag, &metaData_);
158     }
159 
IsTSHClass()160     inline bool IsTSHClass() const
161     {
162         return IsTSHClassField::Get(metaData_);
163     }
164 
SetIsTSHClass(bool flag)165     inline void SetIsTSHClass(bool flag)
166     {
167         IsTSHClassField::Set(flag, &metaData_);
168     }
169 
GetAttr()170     inline PropertyAttributes GetAttr() const
171     {
172         return attributes_;
173     }
174 
SetAttr(uint64_t attr)175     inline void SetAttr(uint64_t attr)
176     {
177         attributes_ = PropertyAttributes(attr);
178     }
179 
SetAttr(const PropertyAttributes & attr)180     inline void SetAttr(const PropertyAttributes &attr)
181     {
182         attributes_ = attr;
183     }
184 
IsPrimitiveAttr()185     inline bool IsPrimitiveAttr() const
186     {
187         return !attributes_.GetValue();
188     }
189 
IsWritable()190     inline bool IsWritable() const
191     {
192         return GetAttr().IsWritable();
193     }
194 
IsEnumerable()195     inline bool IsEnumerable() const
196     {
197         return GetAttr().IsEnumerable();
198     }
199 
IsConfigurable()200     inline bool IsConfigurable() const
201     {
202         return GetAttr().IsConfigurable();
203     }
204 
IsAccessorDescriptor()205     inline bool IsAccessorDescriptor() const
206     {
207         return GetAttr().IsAccessor();
208     }
209 
IsInlinedProps()210     inline bool IsInlinedProps() const
211     {
212         return GetAttr().IsInlinedProps();
213     }
214 
SetIsInlinedProps(bool flag)215     inline void SetIsInlinedProps(bool flag)
216     {
217         attributes_.SetIsInlinedProps(flag);
218     }
219 
GetRepresentation()220     inline Representation GetRepresentation() const
221     {
222         return GetAttr().GetRepresentation();
223     }
224 
GetValue()225     inline JSTaggedValue GetValue() const
226     {
227         if (value_.IsEmpty()) {
228             return JSTaggedValue::Undefined();
229         }
230         return value_.GetTaggedValue();
231     }
232 
233     JSHandle<JSTaggedValue> FastGetValue();
SetValue(JSTaggedValue value)234     inline void SetValue(JSTaggedValue value)
235     {
236         if (value_.IsEmpty()) {
237             value_ = JSMutableHandle<JSTaggedValue>(thread_, value);
238         }
239         value_.Update(value);
240     }
241 
SetIndex(uint32_t index)242     inline void SetIndex(uint32_t index)
243     {
244         index_ = index;
245     }
246 
GetIndex()247     inline uint32_t GetIndex() const
248     {
249         return index_;
250     }
251 
SetElementOutOfBounds(bool val)252     inline void SetElementOutOfBounds(bool val)
253     {
254         elementsOutOfBounds_ = val;
255     }
256 
GetElementOutOfBounds()257     inline bool GetElementOutOfBounds() const
258     {
259         return elementsOutOfBounds_;
260     }
261 
HasHolder()262     inline bool HasHolder() const
263     {
264         return !holder_.IsEmpty();
265     }
266 
GetHolder()267     inline JSHandle<JSTaggedValue> GetHolder() const
268     {
269         return holder_;
270     }
271 
GetReceiver()272     inline JSHandle<JSTaggedValue> GetReceiver() const
273     {
274         return receiver_;
275     }
276 
GetKey()277     inline JSHandle<JSTaggedValue> GetKey() const
278     {
279         if (key_.IsEmpty()) {
280             return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
281         }
282         return key_;
283     }
284 
KeyFromStringType()285     inline bool KeyFromStringType() const
286     {
287         return keyFromStringType_;
288     }
289 
GetElementIndex()290     inline uint32_t GetElementIndex() const
291     {
292         return elementIndex_;
293     }
294 
GetThread()295     inline JSThread *GetThread() const
296     {
297         return thread_;
298     }
299 
300     void ToPropertyDescriptor(PropertyDescriptor &desc) const;
301     SharedFieldType GetSharedFieldType() const;
302     void LookupProperty();
303     void GlobalLookupProperty();
ReLookupPropertyInReceiver()304     inline void ReLookupPropertyInReceiver()
305     {
306         ResetState();
307         return LookupPropertyInlinedProps(JSHandle<JSObject>(receiver_));
308     }
SetAsDefaultAttr()309     inline void SetAsDefaultAttr()
310     {
311         SetFound(NOT_FOUND_INDEX, JSTaggedValue::Undefined(), PropertyAttributes::GetDefaultAttributes(), false, false);
312     }
313     bool UpdateDataValue(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
314                          bool isInternalAccessor, bool mayThrow = false);
WriteDataPropertyInHolder(const PropertyDescriptor & desc)315     bool WriteDataPropertyInHolder(const PropertyDescriptor &desc)
316     {
317         JSHandle<JSObject> receiver(holder_);
318         return WriteDataProperty(receiver, desc);
319     }
320     bool WriteDataProperty(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc);
321     bool AddProperty(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value, PropertyAttributes attr);
AddPropertyInHolder(const JSHandle<JSTaggedValue> & value,PropertyAttributes attr)322     inline bool AddPropertyInHolder(const JSHandle<JSTaggedValue> &value, PropertyAttributes attr)
323     {
324         JSHandle<JSObject> obj(holder_);
325         return AddProperty(obj, value, attr);
326     }
327     void DeletePropertyInHolder();
328     static constexpr uint32_t NOT_FOUND_INDEX = std::numeric_limits<uint32_t>::max();
329     static JSTaggedValue ToHolder(const JSHandle<JSTaggedValue> &holder);
330     void AddPropertyInternal(const JSHandle<JSTaggedValue> &value);
331     void DefineSetter(const JSHandle<JSTaggedValue> &value);
332     void DefineGetter(const JSHandle<JSTaggedValue> &value);
333 
334 private:
335     static constexpr uint64_t ATTR_LENGTH = 5;
336     static constexpr uint64_t INDEX_LENGTH = 32;
337 
338     using IsFastModeField = BitField<bool, 0, 1>;
339     using IsOnPrototypeField = IsFastModeField::NextFlag;  // 1: on prototype
340     using HasReceiverField = IsOnPrototypeField::NextFlag;
341     using IsTransitionField = HasReceiverField::NextFlag;
342     using IsTSHClassField = IsTransitionField::NextFlag;
343     // found dictionary obj between receriver and holder
344     using IsFoundDictField = IsTSHClassField::NextFlag;
345 
346     void UpdateHolder();
347     void UpdateIsTSHClass();
348     void StartLookUp(OperatorType type);
349     void StartGlobalLookUp(OperatorType type);
350     void HandleKey(const JSHandle<JSTaggedValue> &key);
351     uint32_t ComputeElementCapacity(uint32_t oldCapacity);
352     void SetFound(uint32_t index, JSTaggedValue value, uint64_t attr, bool mode, bool transition = false);
353     void UpdateFound(uint32_t index, uint64_t attr, bool mode, bool transition);
354     void ResetState();
355     void ResetStateForAddProperty();
LookupPropertyInHolder()356     inline void LookupPropertyInHolder()
357     {
358         JSHandle<JSObject> obj(holder_);
359         LookupPropertyInlinedProps(obj);
360     }
GlobalLookupPropertyInHolder()361     inline void GlobalLookupPropertyInHolder()
362     {
363         JSHandle<JSObject> obj(holder_);
364         LookupGlobal(obj);
365     }
366     void LookupGlobal(const JSHandle<JSObject> &obj);
367     void LookupPropertyInlinedProps(const JSHandle<JSObject> &obj);
368     void LookupElementInlinedProps(const JSHandle<JSObject> &obj);
369     void WriteElement(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc);
370     void WriteElement(const JSHandle<JSObject> &receiver, JSHandle<JSTaggedValue> value) const;
371     void DeleteElementInHolder() const;
372     bool UpdateValueAndDetails(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
373                                PropertyAttributes attr, bool attrChanged);
374     void TransitionForAttributeChanged(const JSHandle<JSObject> &receiver, PropertyAttributes attr);
375     JSThread *thread_{nullptr};
376     JSMutableHandle<JSTaggedValue> value_{};
377     JSMutableHandle<JSTaggedValue> holder_{};
378     JSMutableHandle<JSTaggedValue> receiver_{};
379     JSHandle<JSTaggedValue> key_{};
380     uint32_t elementIndex_{NOT_FOUND_INDEX};
381     uint32_t index_{NOT_FOUND_INDEX};
382     PropertyAttributes attributes_;
383     uint32_t metaData_{0};
384     int receiverHoleEntry_{-1};
385     bool keyFromStringType_{false};
386     bool elementsOutOfBounds_{false};
387 };
388 }  // namespace panda::ecmascript
389 #endif  // ECMASCRIPT_OBJECT_OPERATOR_H
390