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_JSOBJECT_H
17 #define ECMASCRIPT_JSOBJECT_H
18 
19 #include "ecmascript/ecma_macros.h"
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/filter_helper.h"
22 #include "ecmascript/ic/property_box.h"
23 #include "ecmascript/js_handle.h"
24 #include "ecmascript/js_hclass.h"
25 #include "ecmascript/js_tagged_value.h"
26 #include "ecmascript/mem/layout_visitor.h"
27 #include "ecmascript/mem/slots.h"
28 #include "ecmascript/mem/visitor.h"
29 #include "ecmascript/method.h"
30 #include "ecmascript/property_attributes.h"
31 #include "ecmascript/tagged_array.h"
32 
33 namespace panda {
34 namespace ecmascript {
35 class ObjectOperator;
36 class JSFunction;
37 class AccessorData;
38 class JSArray;
39 class JSForInIterator;
40 class LexicalEnv;
41 class GlobalEnv;
42 class TaggedQueue;
43 class NumberDictionary;
44 
45 namespace builtins {
46     class BuiltinsArkTools;
47 }
48 
49 using EnumCacheKind = EnumCache::EnumCacheKind;
50 using SCheckMode = JSShared::SCheckMode;
51 
52 // Integrity level for objects
53 enum IntegrityLevel { SEALED, FROZEN };
54 
55 enum PositionKind { UNKNOWN = 0, INDEXED_PROPERTY = 1, INLINE_NAMED_PROPERTY = 2, OUT_NAMED_PROPERTY = 3 };
56 enum PropertyKind { KEY = 0, VALUE, KEY_VALUE };
57 
58 // ecma6.0 6.2.4 The Property Descriptor Specification Type
59 class PropertyDescriptor final {
60 public:
61     PropertyDescriptor() = delete;
62 
63     ~PropertyDescriptor() = default;
64     DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyDescriptor);
65     DEFAULT_COPY_SEMANTIC(PropertyDescriptor);
66 
PropertyDescriptor(const JSThread *thread)67     explicit PropertyDescriptor(const JSThread *thread) : thread_(thread) {}
68 
PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v)69     PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v) : thread_(thread), value_(v) {}
70 
PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v, bool w, bool e, bool c)71     PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v, bool w, bool e, bool c)
72         : thread_(thread),
73           writable_(w),
74           enumerable_(e),
75           configurable_(c),
76           hasWritable_(true),
77           hasEnumerable_(true),
78           hasConfigurable_(true),
79           value_(v)
80     {
81     }
82 
PropertyDescriptor(const JSThread *thread, bool w, bool e, bool c)83     PropertyDescriptor(const JSThread *thread, bool w, bool e, bool c)
84         : PropertyDescriptor(thread, JSHandle<JSTaggedValue>(), w, e, c)
85     {
86     }
87 
GetValue() const88     inline JSHandle<JSTaggedValue> GetValue() const
89     {
90         if (value_.IsEmpty()) {
91             return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
92         }
93         return value_;
94     }
95 
GetKey() const96     inline JSHandle<JSTaggedValue> GetKey() const
97     {
98         if (key_.IsEmpty()) {
99             return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
100         }
101         return key_;
102     }
103 
SetValue(JSHandle<JSTaggedValue> value)104     inline void SetValue(JSHandle<JSTaggedValue> value)
105     {
106         value_ = value;
107     }
108 
SetKey(JSHandle<JSTaggedValue> key)109     inline void SetKey(JSHandle<JSTaggedValue> key)
110     {
111         key_ = key;
112     }
113 
SetSharedFieldType(SharedFieldType fieldType)114     inline void SetSharedFieldType(SharedFieldType fieldType)
115     {
116         fieldType_ = fieldType;
117     }
118 
GetSharedFieldType() const119     inline SharedFieldType GetSharedFieldType() const
120     {
121         return fieldType_;
122     }
123 
IsWritable() const124     inline bool IsWritable() const
125     {
126         return writable_;
127     }
128 
SetWritable(bool flag)129     inline void SetWritable(bool flag)
130     {
131         writable_ = flag;
132         hasWritable_ = true;
133     }
134 
IsEnumerable() const135     inline bool IsEnumerable() const
136     {
137         return enumerable_;
138     }
139 
SetEnumerable(bool flag)140     inline void SetEnumerable(bool flag)
141     {
142         enumerable_ = flag;
143         hasEnumerable_ = true;
144     }
145 
IsConfigurable() const146     inline bool IsConfigurable() const
147     {
148         return configurable_;
149     }
150 
SetConfigurable(bool flag)151     inline void SetConfigurable(bool flag)
152     {
153         configurable_ = flag;
154         hasConfigurable_ = true;
155     }
156 
HasValue() const157     inline bool HasValue() const
158     {
159         return !value_.IsEmpty();
160     }
161 
HasWritable() const162     inline bool HasWritable() const
163     {
164         return hasWritable_;
165     }
166 
HasConfigurable() const167     inline bool HasConfigurable() const
168     {
169         return hasConfigurable_;
170     }
171 
HasEnumerable() const172     inline bool HasEnumerable() const
173     {
174         return hasEnumerable_;
175     }
176 
HasGetter() const177     inline bool HasGetter() const
178     {
179         return !getter_.IsEmpty();
180     }
181 
HasSetter() const182     inline bool HasSetter() const
183     {
184         return !setter_.IsEmpty();
185     }
186 
GetGetter() const187     inline JSHandle<JSTaggedValue> GetGetter() const
188     {
189         if (getter_->IsNull()) {
190             return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
191         }
192         return getter_;
193     }
194 
GetSetter() const195     inline JSHandle<JSTaggedValue> GetSetter() const
196     {
197         if (setter_->IsNull()) {
198             return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
199         }
200         return setter_;
201     }
202 
SetGetter(JSHandle<JSTaggedValue> value)203     inline void SetGetter(JSHandle<JSTaggedValue> value)
204     {
205         getter_ = value;
206     }
207 
SetSetter(JSHandle<JSTaggedValue> value)208     inline void SetSetter(JSHandle<JSTaggedValue> value)
209     {
210         setter_ = value;
211     }
212 
213     // 6.2.4.1
IsAccessorDescriptor() const214     inline bool IsAccessorDescriptor() const
215     {
216         // 2. If both Desc.[[Get]] and Desc.[[Set]] are absent, return false.
217         return !(getter_.IsEmpty() && setter_.IsEmpty());
218     }
219 
IsDataDescriptor() const220     inline bool IsDataDescriptor() const
221     {
222         // 2. If both Desc.[[Value]] and Desc.[[Writable]] are absent, return false.
223         return !(value_.IsEmpty() && !hasWritable_);
224     }
225 
IsGenericDescriptor() const226     inline bool IsGenericDescriptor() const
227     {
228         // 2. If IsAccessorDescriptor(Desc) and IsDataDescriptor(Desc) are both false, return true
229         return !IsAccessorDescriptor() && !IsDataDescriptor();
230     }
231 
IsEmpty() const232     inline bool IsEmpty() const
233     {
234         return !hasWritable_ && !hasEnumerable_ && !hasConfigurable_ && !HasValue() && !HasGetter() && !HasSetter();
235     }
236 
237     static void CompletePropertyDescriptor(const JSThread *thread, PropertyDescriptor &desc);
238 
239 private:
240     const JSThread *thread_{nullptr};
241 
242     bool writable_ {false};
243     bool enumerable_ {false};
244     bool configurable_ {false};
245     bool hasWritable_ {false};
246     bool hasEnumerable_ {false};
247     bool hasConfigurable_ {false};
248     SharedFieldType fieldType_ {SharedFieldType::NONE};
249 
250     JSHandle<JSTaggedValue> value_ {};
251     JSHandle<JSTaggedValue> getter_ {};
252     JSHandle<JSTaggedValue> setter_ {};
253     JSHandle<JSTaggedValue> key_ {};
254 };
255 
256 enum class ElementTypes { ALLTYPES, STRING_AND_SYMBOL };
257 
258 class PropertyMetaData {
259 public:
260     using IsFoundField = BitField<bool, 0, 1>;
261     using IsInlinedPropsField = IsFoundField::NextFlag;
262     // 3: The bit field that represents the "Representation" of the property
263     using RepresentationField = IsInlinedPropsField::NextField<Representation, 3>;
264     using OffsetField = RepresentationField::NextField<uint32_t, PropertyAttributes::OFFSET_BITFIELD_NUM>;
265 
PropertyMetaData(uint32_t metaData)266     explicit PropertyMetaData(uint32_t metaData) : metaData_(metaData) {}
267 
268     ~PropertyMetaData() = default;
269     DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyMetaData);
270     DEFAULT_COPY_SEMANTIC(PropertyMetaData);
271 
PropertyMetaData(bool isFound)272     explicit PropertyMetaData(bool isFound)
273     {
274         SetFound(isFound);
275     }
276 
IsFound() const277     inline bool IsFound() const
278     {
279         return IsFoundField::Get(metaData_);
280     }
281 
SetFound(bool flag)282     inline void SetFound(bool flag)
283     {
284         IsFoundField::Set(flag, &metaData_);
285     }
286 
GetIsInlinedProps() const287     inline bool GetIsInlinedProps() const
288     {
289         return IsInlinedPropsField::Get(metaData_);
290     }
291 
SetIsInlinedProps(bool flag)292     inline void SetIsInlinedProps(bool flag)
293     {
294         IsInlinedPropsField::Set(flag, &metaData_);
295     }
296 
GetRepresentation() const297     inline Representation GetRepresentation() const
298     {
299         return RepresentationField::Get(metaData_);
300     }
301 
SetRepresentation(Representation representation)302     inline void SetRepresentation(Representation representation)
303     {
304         RepresentationField::Set<uint32_t>(representation, &metaData_);
305     }
306 
SetOffset(uint32_t offset)307     inline void SetOffset(uint32_t offset)
308     {
309         OffsetField::Set<uint32_t>(offset, &metaData_);
310     }
311 
GetOffset() const312     inline uint32_t GetOffset() const
313     {
314         return OffsetField::Get(metaData_);
315     }
316 
317 private:
318     uint32_t metaData_{0};
319 };
320 
321 class OperationResult {
322 public:
OperationResult(const JSThread *thread, JSTaggedValue value, PropertyMetaData metaData)323     OperationResult(const JSThread *thread, JSTaggedValue value, PropertyMetaData metaData)
324         : metaData_(metaData)
325     {
326         thread_ = thread;
327         value_ = JSHandle<JSTaggedValue>(thread_, value);
328     }
329 
330     ~OperationResult() = default;
331     DEFAULT_NOEXCEPT_MOVE_SEMANTIC(OperationResult);
332     DEFAULT_COPY_SEMANTIC(OperationResult);
333 
GetValue() const334     JSHandle<JSTaggedValue> GetValue() const
335     {
336         if (value_->IsPropertyBox()) {
337             return JSHandle<JSTaggedValue>(thread_,
338                                            PropertyBox::Cast(value_.GetTaggedValue().GetTaggedObject())->GetValue());
339         }
340         return value_;
341     }
342 
GetRawValue() const343     JSHandle<JSTaggedValue> GetRawValue() const
344     {
345         return value_;
346     }
347 
GetPropertyMetaData() const348     const PropertyMetaData &GetPropertyMetaData() const
349     {
350         return metaData_;
351     }
352 
353 private:
354     const JSThread *thread_ {nullptr};
355     JSHandle<JSTaggedValue> value_ {};
356     PropertyMetaData metaData_ {0U};
357 };
358 
359 
360 // HashField possible layout:
361 // [ hashValue ] | [extraInfo] | [ hashValue, extraInfo, nativePointer, ... ]
362 // nativePointer number depends on the extraLength of taggedArray
363 class ECMAObject : public TaggedObject {
364 public:
365     static constexpr int HASH_INDEX = 0;
366     static constexpr int FUNCTION_EXTRA_INDEX = 1;
367     static constexpr int RESOLVED_MAX_SIZE = 2;
368 
369     CAST_CHECK(ECMAObject, IsECMAObject);
370 
371     void SetCallable(bool flag);
372     bool IsCallable() const;
373     Method *GetCallTarget() const;
374 
375     static constexpr size_t HASH_OFFSET = TaggedObjectSize();
376     static constexpr size_t SIZE = HASH_OFFSET + sizeof(JSTaggedType);
377 
378     static void SetHash(const JSThread *thread, int32_t hash, const JSHandle<ECMAObject> &obj);
379     int32_t GetHash() const;
380     bool HasHash() const;
381 
InitializeHash()382     void InitializeHash()
383     {
384         Barriers::SetPrimitive<JSTaggedType>(this, ECMAObject::HASH_OFFSET, JSTaggedValue(0).GetRawData());
385     }
386 
387     void* GetNativePointerField(int32_t index) const;
388     void SetNativePointerField(const JSThread *thread, int32_t index, void *nativePointer,
389                                const NativePointerCallback &callBack, void *data, size_t nativeBindingsize = 0,
390                                Concurrent isConcurrent = Concurrent::NO);
391     int32_t GetNativePointerFieldCount() const;
392     void SetNativePointerFieldCount(const JSThread *thread, int32_t count);
393 
394     DECL_VISIT_OBJECT(HASH_OFFSET, SIZE);
395 
396     template <VisitType visitType>
VisitObjects(const EcmaObjectRangeVisitor &visitor)397     void VisitObjects(const EcmaObjectRangeVisitor &visitor)
398     {
399         // no field in this object
400         VisitRangeSlot<visitType>(visitor);
401     }
402 };
403 
404 class JSObject : public ECMAObject {
405 public:
406     static constexpr int MIN_ELEMENTS_LENGTH = 3;
407     static constexpr int MIN_PROPERTIES_LENGTH = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS;
408     static constexpr int FAST_ELEMENTS_FACTOR = 3;
409     static constexpr int MIN_GAP = 256;
410     static constexpr int MAX_GAP = 1_KB;
411     static constexpr uint32_t MAX_ELEMENT_INDEX = std::numeric_limits<uint32_t>::max();
412     static constexpr int MIN_ELEMENTS_HINT_LENGTH = 1_KB;
413     static constexpr int MAX_ELEMENTS_HINT_LENGTH = 2_MB;
414     static constexpr int ELEMENTS_HINT_FACTOR = 8;
415     static constexpr int SHOULD_TRANS_TO_FAST_ELEMENTS_FACTOR = 2;
416 
417     CAST_CHECK(JSObject, IsECMAObject);
418 
419     // ecma6.0 6.2.4.4
420     static JSHandle<JSTaggedValue> FromPropertyDescriptor(JSThread *thread, const PropertyDescriptor &desc);
421 
422     // ecma6.0 6.2.4.5 ToPropertyDescriptor ( Obj )
423     static void ToPropertyDescriptor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc);
424     static bool ToPropertyDescriptorFast(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
425                                          PropertyDescriptor &desc);
426 
427     static JSHandle<JSTaggedValue> CallFunction(JSThread *thread, const JSHandle<JSTaggedValue> &func);
428 
429     // ecma6 7.3 Operations on Objects
430     static JSHandle<JSTaggedValue> GetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
431                                              const JSHandle<JSTaggedValue> &key);
432 
433     static JSHandle<JSTaggedValue> FastGetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
434                                                  const JSHandle<JSTaggedValue> &key);
435 
436     static bool CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
437                                    const JSHandle<JSTaggedValue> &value, SCheckMode sCheckMode = SCheckMode::CHECK);
438 
439     static bool CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
440                                    const JSHandle<JSTaggedValue> &value, SCheckMode sCheckMode = SCheckMode::CHECK);
441 
442     static bool CreateMethodProperty(JSThread *thread, const JSHandle<JSObject> &obj,
443                                      const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value);
444 
445     static bool CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj,
446                                           const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
447                                           SCheckMode sCheckMode = SCheckMode::CHECK);
448 
449     static bool CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
450                                           const JSHandle<JSTaggedValue> &value,
451                                           SCheckMode sCheckMode = SCheckMode::CHECK);
452 
453     static JSHandle<TaggedArray> PUBLIC_API EnumerableOwnNames(JSThread *thread, const JSHandle<JSObject> &obj);
454 
455     // 7.3.23 EnumerableOwnPropertyNames ( O, kind )
456     static JSHandle<TaggedArray> EnumerableOwnPropertyNames(JSThread *thread, const JSHandle<JSObject> &obj,
457                                                             PropertyKind kind);
458     static void EnumerableOwnPropertyNamesHelper(JSThread *thread, const JSHandle<JSObject> &obj,
459         const JSHandle<TaggedArray> &arr, JSHandle<TaggedArray> &properties,
460         uint32_t &index, bool &fastMode, PropertyKind kind);
461 
462     static JSHandle<GlobalEnv> GetFunctionRealm(JSThread *thread, const JSHandle<JSTaggedValue> &object);
463 
464     static bool SetIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level);
465 
466     static bool FreezeSharedObject(JSThread *thread, const JSHandle<JSObject> &obj);
467 
468     static bool TestIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level);
469 
470     static JSHandle<JSTaggedValue> SpeciesConstructor(JSThread *thread, const JSHandle<JSObject> &obj,
471                                                       const JSHandle<JSTaggedValue> &defaultConstructor);
472     static JSHandle<JSTaggedValue> SlowSpeciesConstructor(JSThread *thread,
473                                                           const JSHandle<JSTaggedValue> &objConstructor,
474                                                           const JSHandle<JSTaggedValue> &defaultConstructor);
475     // 7.3.17
476     template<ElementTypes types = ElementTypes::ALLTYPES>
477     static JSHandle<JSTaggedValue> CreateListFromArrayLike(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
478 
479     // ecma6 9.1
480     // [[GetPrototypeOf]]
481     static JSTaggedValue GetPrototype(const JSHandle<JSObject> &obj);
482 
483     static JSTaggedValue GetPrototype(JSTaggedValue obj);
484 
485     // [[SetPrototypeOf]]
486     static bool SetPrototype(JSThread *thread, const JSHandle<JSObject> &obj,
487                              const JSHandle<JSTaggedValue> &proto,
488                              bool isChangeProto = false);
489 
490     // [[IsExtensible]]
491     bool IsExtensible() const;
492 
493     // [[PreventExtensions]]
494     static bool PreventExtensions(JSThread *thread, const JSHandle<JSObject> &obj);
495 
496     // [[GetOwnProperty]] -> Undefined | Property Descriptor
497     static bool GetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
498                                PropertyDescriptor &desc);
499 
500     static bool GlobalGetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc);
501 
502     static bool OrdinaryGetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
503                                        const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc);
504 
505     // [[DefineOwnProperty]]
506     static bool DefineOwnProperty(JSThread *thread, ObjectOperator *op,
507                                   const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK);
508 
509     static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
510                                   const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK);
511 
512     static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
513                                   const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK);
514 
515     static bool OrdinaryDefineOwnProperty(JSThread *thread, ObjectOperator *op,
516                                           const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK);
517 
518     static bool OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
519                                           const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc,
520                                           SCheckMode sCheckMode = SCheckMode::CHECK);
521 
522     static bool OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
523                                           const PropertyDescriptor &desc,
524                                           SCheckMode sCheckMode = SCheckMode::CHECK);
525 
526     static bool IsCompatiblePropertyDescriptor(bool extensible, const PropertyDescriptor &desc,
527                                                const PropertyDescriptor &current);
528 
529     static bool ValidateAndApplyPropertyDescriptor(ObjectOperator *op, bool extensible, const PropertyDescriptor &desc,
530                                                    const PropertyDescriptor &current,
531                                                    SCheckMode sCheckMode = SCheckMode::CHECK);
532 
533     static OperationResult PUBLIC_API GetProperty(JSThread *thread, const JSHandle<JSObject> &obj,
534                                                   const JSHandle<JSTaggedValue> &key);
535 
536     static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
537                                        const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver);
538 
539     static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
540                                        const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode = SCheckMode::CHECK);
541 
542     static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index);
543 
544     static OperationResult GetPropertyFromGlobal(JSThread *thread, const JSHandle<JSTaggedValue> &key);
545 
546     static bool SetProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
547                             const JSHandle<JSTaggedValue> &value, bool mayThrow = false);
548 
549     static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
550                             const JSHandle<JSTaggedValue> &value, bool mayThrow = false,
551                             SCheckMode checkMode = SCheckMode::CHECK);
552 
553     static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
554                             const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &receiver,
555                             bool mayThrow = false);
556 
557     static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index,
558                             const JSHandle<JSTaggedValue> &value, bool mayThrow = false);
559 
560     static bool GlobalSetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key,
561                                   const JSHandle<JSTaggedValue> &value, bool mayThrow);
562 
563     // [[HasProperty]]
564     static bool HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key);
565 
566     static bool HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index);
567 
568     // 9.1.10 [[Delete]]
569     static bool DeleteProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
570                                SCheckMode sCheckMode = SCheckMode::CHECK);
571 
572     // [[OwnPropertyKeys]]
573     static JSHandle<TaggedArray> GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj);
574 
575     static JSHandle<TaggedArray> GetAllPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t filter);
576 
577     static void CollectEnumKeysAlongProtoChain(JSThread *thread, const JSHandle<JSObject> &obj,
578                                                JSHandle<TaggedArray> keyArray, uint32_t *keys,
579                                                JSHandle<TaggedQueue> shadowQueue, int32_t lastLength = -1);
580 
581     static void AppendOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj,
582                                           JSHandle<TaggedArray> keyArray, uint32_t *keys,
583                                           JSHandle<TaggedQueue> shadowQueue);
584 
585     static JSHandle<TaggedArray> GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj);
586 
587     // 9.1.13 ObjectCreate
588     static JSHandle<JSObject> ObjectCreate(JSThread *thread, const JSHandle<JSObject> &proto);
589 
590     // 12.9.4 Runtime Semantics: InstanceofOperator(O, C)
591     static bool InstanceOf(JSThread *thread, const JSHandle<JSTaggedValue> &object,
592                            const JSHandle<JSTaggedValue> &target);
593 
594     static JSTaggedValue TryGetEnumCache(JSThread *thread, JSTaggedValue obj);
595 
596     // 13.7.5.15 EnumerateObjectProperties ( O ); same as [[Enumerate]]
597     static JSHandle<JSForInIterator> EnumerateObjectProperties(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
598     static JSHandle<JSForInIterator> LoadEnumerateProperties(JSThread *thread, const JSHandle<JSTaggedValue> &object);
599 
600     static bool IsRegExp(JSThread *thread, const JSHandle<JSTaggedValue> &argument);
601 
602     static JSTaggedValue CallGetter(JSThread *thread, const AccessorData *accessor,
603                                     const JSHandle<JSTaggedValue> &receiver);
604     static bool PUBLIC_API CallSetter(JSThread *thread, const AccessorData &accessor,
605                                       const JSHandle<JSTaggedValue> &receiver,
606                                       const JSHandle<JSTaggedValue> &value, bool mayThrow = false);
607 
608     void FillElementsWithHoles(const JSThread *thread, uint32_t start, uint32_t end);
609 
GetJSHClass() const610     JSHClass *GetJSHClass() const
611     {
612         return GetClass();
613     }
614     uint32_t GetNonInlinedFastPropsCapacity() const;
615     bool IsJSGlobalObject() const;
616     bool IsConstructor() const;
617     bool IsECMAObject() const;
618     bool IsJSError() const;
619     bool IsArguments() const;
620     bool IsDate() const;
621     bool IsJSArray() const;
622     bool IsJSSArray() const;
623     bool IsJSShared() const;
624     bool IsJSMap() const;
625     bool IsJSSet() const;
626     bool IsJSRegExp() const;
627     bool IsJSFunction() const;
628     bool IsBoundFunction() const;
629     bool IsJSIntlBoundFunction() const;
630     bool IsProxyRevocFunction() const;
631     bool IsAccessorData() const;
632     bool IsJSGlobalEnv() const;
633     bool IsJSProxy() const;
634     bool IsGeneratorObject() const;
635     bool IsAsyncGeneratorObject() const;
636     bool IsForinIterator() const;
637     bool IsJSSetIterator() const;
638     bool IsJSRegExpIterator() const;
639     bool IsJSMapIterator() const;
640     bool IsJSArrayIterator() const;
641     bool IsJSAPIArrayListIterator() const;
642     bool IsJSAPIStackIterator() const;
643     bool IsJSAPIVectorIterator() const;
644     bool IsJSAPIBitVectorIterator() const;
645     bool IsJSAPILinkedListIterator() const;
646     bool IsJSAPIListIterator() const;
647     bool IsJSPrimitiveRef() const;
648     bool IsElementDict() const;
649     bool IsPropertiesDict() const;
650     bool IsTypedArray() const;
651     bool PUBLIC_API ElementsAndPropertiesIsEmpty() const;
652 
653     static PUBLIC_API void DefinePropertyByLiteral(JSThread *thread, const JSHandle<JSObject> &obj,
654                                                    const JSHandle<JSTaggedValue> &key,
655                                                    const JSHandle<JSTaggedValue> &value,
656                                                    bool useForClass = false);
657     static void DefineSetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
658                              const JSHandle<JSTaggedValue> &value);
659     static void DefineGetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
660                              const JSHandle<JSTaggedValue> &value);
661     static PUBLIC_API JSHandle<JSObject> CreateObjectFromProperties(const JSThread *thread,
662                                                                     const JSHandle<TaggedArray> &properties,
663                                                          JSTaggedValue ihc = JSTaggedValue::Undefined());
664     static JSHandle<JSObject> CreateObjectFromProperties(const JSThread *thread,
665                                                          const JSHandle<JSHClass> &hclass,
666                                                          const JSHandle<TaggedArray> &properties,
667                                                          uint32_t propsLen);
668     static JSHandle<JSObject> CreateObjectFromPropertiesByIHClass(const JSThread *thread,
669                                                                   const JSHandle<TaggedArray> &properties,
670                                                                   uint32_t propsLen,
671                                                                   const JSHandle<JSHClass> &ihc);
672     static bool CheckPropertiesForRep(
673         const JSHandle<TaggedArray> &properties, uint32_t propsLen, const JSHandle<JSHClass> &ihc);
674     static void GetAllKeys(const JSThread *thread, const JSHandle<JSObject> &obj, int offset,
675                            const JSHandle<TaggedArray> &keyArray);
676     static void GetAllKeysForSerialization(const JSHandle<JSObject> &obj, std::vector<JSTaggedValue> &keyVector);
677 
678     static void GetAllKeysByFilter(const JSThread *thread, const JSHandle<JSObject> &obj,
679                                    uint32_t &keyArrayEffectivelength,
680                                    const JSHandle<TaggedArray> &keyArray,
681                                    uint32_t filter);
682     static void GetAllElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
683                                   const JSHandle<TaggedArray> &keyArray);
684     static void GetAllElementKeysByFilter(JSThread *thread,
685                                           const JSHandle<JSObject> &obj,
686                                           const JSHandle<TaggedArray> &keyArray,
687                                           uint32_t &keyArrayEffectiveLength,
688                                           uint32_t filter);
689 
690     static void GetALLElementKeysIntoVector(const JSThread *thread, const JSHandle<JSObject> &obj,
691                                             std::vector<JSTaggedValue> &keyVector);
692     std::pair<uint32_t, uint32_t> GetNumberOfEnumKeys() const;
693     uint32_t GetNumberOfKeys();
694     uint32_t GetNumberOfElements();
695 
696     static JSHandle<TaggedArray> GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
697                                                     uint32_t numOfElements, uint32_t *keys);
698     static void CollectEnumElementsAlongProtoChain(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
699                                                    JSHandle<TaggedArray> elementArray, uint32_t *keys,
700                                                    int32_t lastLength = -1);
701     static void GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
702                                    const JSHandle<TaggedArray> &keyArray);
703     static JSHandle<TaggedArray> GetAllEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj,
704                                                 uint32_t numOfKeys, uint32_t *keys);
705     static uint32_t GetAllEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
706                                    const JSHandle<TaggedArray> &keyArray);
707 
708     static void AddAccessor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
709                             const JSHandle<AccessorData> &value, PropertyAttributes attr);
710 
711     static constexpr size_t PROPERTIES_OFFSET = ECMAObject::SIZE;
712 
713     ACCESSORS(Properties, PROPERTIES_OFFSET, ELEMENTS_OFFSET);
714     ACCESSORS(Elements, ELEMENTS_OFFSET, SIZE);
715 
716     DECL_VISIT_OBJECT_FOR_JS_OBJECT(ECMAObject, PROPERTIES_OFFSET, SIZE)
717 
718     DECL_DUMP()
719     static const CString ExtractConstructorAndRecordName(JSThread *thread, TaggedObject *obj, bool noAllocate = false,
720                                                          bool *isCallGetter = nullptr);
721 
722     static JSHandle<NameDictionary> PUBLIC_API TransitionToDictionary(const JSThread *thread,
723                                                                       const JSHandle<JSObject> &receiver);
724 
725     static inline std::pair<bool, JSTaggedValue> ConvertValueWithRep(PropertyAttributes attr, JSTaggedValue value);
726 
727     inline void SetPropertyInlinedPropsWithRep(const JSThread *thread, uint32_t index, JSTaggedValue value);
728     template <bool needBarrier = true>
729     inline void SetPropertyInlinedProps(const JSThread *thread, uint32_t index, JSTaggedValue value);
730     template <bool needBarrier = true>
731     inline void SetPropertyInlinedProps(const JSThread *thread, const JSHClass *hclass, uint32_t index,
732                                         JSTaggedValue value);
733     inline JSTaggedValue GetPropertyInlinedPropsWithRep(uint32_t index, PropertyAttributes attr) const;
734     inline JSTaggedValue GetPropertyInlinedPropsWithRep(const JSHClass *hclass, uint32_t index,
735         PropertyAttributes attr) const;
736     inline JSTaggedValue GetPropertyInlinedProps(uint32_t index) const;
737     inline JSTaggedValue GetPropertyInlinedProps(const JSHClass *hclass, uint32_t index) const;
738     inline JSTaggedValue GetProperty(const JSHClass *hclass, PropertyAttributes attr) const;
739     PropertyBox* GetGlobalPropertyBox(JSThread *thread, const std::string& key);
740     template <bool needBarrier = true>
741     inline void SetProperty(const JSThread *thread, const JSHClass *hclass, PropertyAttributes attr,
742                             JSTaggedValue value);
743 
744     static bool IsArrayLengthWritable(JSThread *thread, const JSHandle<JSObject> &receiver);
745     bool UpdatePropertyInDictionary(const JSThread *thread, JSTaggedValue key, JSTaggedValue value);
746     static bool ShouldTransToDict(uint32_t capacity, uint32_t index);
747     static bool ShouldTransToFastElements(JSThread *thread, TaggedArray *elements, uint32_t capacity, uint32_t index);
748     static bool ShouldOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj);
749     static JSHandle<TaggedArray> GrowElementsCapacity(const JSThread *thread, const JSHandle<JSObject> &obj,
750                                                       uint32_t capacity, bool highGrowth = false, bool isNew = false);
751 
752     static bool IsDepulicateKeys(JSThread *thread, JSHandle<TaggedArray> keys, int32_t lastLength,
753                                  JSHandle<TaggedQueue> shadowQueue, JSHandle<JSTaggedValue> key);
754 
755     static void SetEnumCacheKind(JSThread *thread, TaggedArray *array, EnumCacheKind kind);
756     static EnumCacheKind GetEnumCacheKind(JSThread *thread, TaggedArray *array);
757     static EnumCacheKind GetEnumCacheKind(JSThread *thread, JSTaggedValue enumCache);
758 
759     static void ClearHasDeleteProperty(JSHandle<JSTaggedValue> object);
760 
761     static JSHandle<JSTaggedValue> IterableToList(JSThread *thread, const JSHandle<JSTaggedValue> &items,
762                                                   JSTaggedValue method = JSTaggedValue::Undefined());
763 
764     static void TryOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj);
765     static void OptimizeAsFastProperties(const JSThread *thread, JSHandle<JSObject> obj);
766 
767     static void SetSProperties(JSThread *thread, JSHandle<JSObject> obj, const std::vector<PropertyDescriptor> &descs);
768 
769     static void PUBLIC_API TryMigrateToGenericKindForJSObject(const JSThread *thread, const JSHandle<JSObject> &obj,
770                                                   const ElementsKind oldKind);
771 protected:
772     static void ElementsToDictionary(const JSThread *thread, JSHandle<JSObject> obj);
773 
774 private:
775     friend class ObjectOperator;
776     friend class LoadICRuntime;
777     friend class StoreICRuntime;
778     friend class ObjectFastOperator;
779     friend class ICRuntimeStub;
780     friend class RuntimeStubs;
781     friend class JSSharedArray;
782     friend class builtins::BuiltinsArkTools;
783 
784     static bool HasMutantTaggedArrayElements(const JSHandle<JSObject> &obj);
785     PropertyBox* GetGlobalPropertyBox(JSTaggedValue key);
786     static bool PUBLIC_API AddElementInternal(
787         JSThread *thread, const JSHandle<JSObject> &receiver, uint32_t index, const JSHandle<JSTaggedValue> &value,
788         PropertyAttributes attr = PropertyAttributes(PropertyAttributes::GetDefaultAttributes()));
789 
790     static JSTaggedValue GetProperty(JSThread *thread, ObjectOperator *op);
791     static bool SetProperty(ObjectOperator *op, const JSHandle<JSTaggedValue> &value, bool mayThrow);
792     static void DeletePropertyInternal(JSThread *thread, const JSHandle<JSObject> &obj,
793                                        const JSHandle<JSTaggedValue> &key, uint32_t index);
794     int FindProperty(const JSHandle<JSTaggedValue> &key);
795 
796     static uint32_t ComputeElementCapacity(uint32_t oldCapacity, bool isNew = false);
797     static uint32_t ComputeElementCapacityHighGrowth(uint32_t oldCapacity);
798     static uint32_t ComputeElementCapacityWithHint(uint32_t oldCapacity, uint32_t hint);
799     static uint32_t ComputeNonInlinedFastPropsCapacity(JSThread *thread, uint32_t oldCapacity,
800                                                        uint32_t maxNonInlinedFastPropsCapacity);
801 
802     static JSTaggedValue ShouldGetValueFromBox(ObjectOperator *op);
803     static std::pair<JSHandle<TaggedArray>, JSHandle<TaggedArray>> GetOwnEnumerableNamesInFastMode(
804         JSThread *thread, const JSHandle<JSObject> &obj, uint32_t *copyLengthOfKeys, uint32_t *copyLengthOfElements);
805     static bool CheckHClassHit(const JSHandle<JSObject> &obj, const JSHandle<JSHClass> &cls);
806     static uint32_t SetValuesOrEntries(JSThread *thread, const JSHandle<TaggedArray> &prop, uint32_t index,
807                                        const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
808                                        PropertyKind kind);
809     static bool IsSimpleEnumCacheValid(JSTaggedValue receiver);
810     static bool IsEnumCacheWithProtoChainInfoValid(JSTaggedValue receiver);
811     static void TrimInlinePropsSpace(const JSThread *thread, const JSHandle<JSObject> &object,
812                                      uint32_t numberInlinedProps);
813     static bool ValidateDataDescriptorWhenConfigurable(ObjectOperator *op, const PropertyDescriptor &desc,
814                                                        const PropertyDescriptor &current, SCheckMode sCheckMode);
815     static bool SetPropertyForDataDescriptor(ObjectOperator *op, const JSHandle<JSTaggedValue> &value,
816                                              JSHandle<JSTaggedValue> &receiver, bool mayThrow, bool isInternalAccessor);
817     static bool SetPropertyForDataDescriptorProxy(JSThread *thread, ObjectOperator *op,
818                                                   const JSHandle<JSTaggedValue> &value,
819                                                   JSHandle<JSTaggedValue> &receiver);
820 };
821 }  // namespace ecmascript
822 }  // namespace panda
823 
824 #endif
825