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
33namespace panda {
34namespace ecmascript {
35class ObjectOperator;
36class JSFunction;
37class AccessorData;
38class JSArray;
39class JSForInIterator;
40class LexicalEnv;
41class GlobalEnv;
42class TaggedQueue;
43class NumberDictionary;
44
45namespace builtins {
46    class BuiltinsArkTools;
47}
48
49using EnumCacheKind = EnumCache::EnumCacheKind;
50using SCheckMode = JSShared::SCheckMode;
51
52// Integrity level for objects
53enum IntegrityLevel { SEALED, FROZEN };
54
55enum PositionKind { UNKNOWN = 0, INDEXED_PROPERTY = 1, INLINE_NAMED_PROPERTY = 2, OUT_NAMED_PROPERTY = 3 };
56enum PropertyKind { KEY = 0, VALUE, KEY_VALUE };
57
58// ecma6.0 6.2.4 The Property Descriptor Specification Type
59class PropertyDescriptor final {
60public:
61    PropertyDescriptor() = delete;
62
63    ~PropertyDescriptor() = default;
64    DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyDescriptor);
65    DEFAULT_COPY_SEMANTIC(PropertyDescriptor);
66
67    explicit PropertyDescriptor(const JSThread *thread) : thread_(thread) {}
68
69    PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v) : thread_(thread), value_(v) {}
70
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
83    PropertyDescriptor(const JSThread *thread, bool w, bool e, bool c)
84        : PropertyDescriptor(thread, JSHandle<JSTaggedValue>(), w, e, c)
85    {
86    }
87
88    inline JSHandle<JSTaggedValue> GetValue() const
89    {
90        if (value_.IsEmpty()) {
91            return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
92        }
93        return value_;
94    }
95
96    inline JSHandle<JSTaggedValue> GetKey() const
97    {
98        if (key_.IsEmpty()) {
99            return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
100        }
101        return key_;
102    }
103
104    inline void SetValue(JSHandle<JSTaggedValue> value)
105    {
106        value_ = value;
107    }
108
109    inline void SetKey(JSHandle<JSTaggedValue> key)
110    {
111        key_ = key;
112    }
113
114    inline void SetSharedFieldType(SharedFieldType fieldType)
115    {
116        fieldType_ = fieldType;
117    }
118
119    inline SharedFieldType GetSharedFieldType() const
120    {
121        return fieldType_;
122    }
123
124    inline bool IsWritable() const
125    {
126        return writable_;
127    }
128
129    inline void SetWritable(bool flag)
130    {
131        writable_ = flag;
132        hasWritable_ = true;
133    }
134
135    inline bool IsEnumerable() const
136    {
137        return enumerable_;
138    }
139
140    inline void SetEnumerable(bool flag)
141    {
142        enumerable_ = flag;
143        hasEnumerable_ = true;
144    }
145
146    inline bool IsConfigurable() const
147    {
148        return configurable_;
149    }
150
151    inline void SetConfigurable(bool flag)
152    {
153        configurable_ = flag;
154        hasConfigurable_ = true;
155    }
156
157    inline bool HasValue() const
158    {
159        return !value_.IsEmpty();
160    }
161
162    inline bool HasWritable() const
163    {
164        return hasWritable_;
165    }
166
167    inline bool HasConfigurable() const
168    {
169        return hasConfigurable_;
170    }
171
172    inline bool HasEnumerable() const
173    {
174        return hasEnumerable_;
175    }
176
177    inline bool HasGetter() const
178    {
179        return !getter_.IsEmpty();
180    }
181
182    inline bool HasSetter() const
183    {
184        return !setter_.IsEmpty();
185    }
186
187    inline JSHandle<JSTaggedValue> GetGetter() const
188    {
189        if (getter_->IsNull()) {
190            return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
191        }
192        return getter_;
193    }
194
195    inline JSHandle<JSTaggedValue> GetSetter() const
196    {
197        if (setter_->IsNull()) {
198            return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
199        }
200        return setter_;
201    }
202
203    inline void SetGetter(JSHandle<JSTaggedValue> value)
204    {
205        getter_ = value;
206    }
207
208    inline void SetSetter(JSHandle<JSTaggedValue> value)
209    {
210        setter_ = value;
211    }
212
213    // 6.2.4.1
214    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
220    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
226    inline bool IsGenericDescriptor() const
227    {
228        // 2. If IsAccessorDescriptor(Desc) and IsDataDescriptor(Desc) are both false, return true
229        return !IsAccessorDescriptor() && !IsDataDescriptor();
230    }
231
232    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
239private:
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
256enum class ElementTypes { ALLTYPES, STRING_AND_SYMBOL };
257
258class PropertyMetaData {
259public:
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
266    explicit PropertyMetaData(uint32_t metaData) : metaData_(metaData) {}
267
268    ~PropertyMetaData() = default;
269    DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyMetaData);
270    DEFAULT_COPY_SEMANTIC(PropertyMetaData);
271
272    explicit PropertyMetaData(bool isFound)
273    {
274        SetFound(isFound);
275    }
276
277    inline bool IsFound() const
278    {
279        return IsFoundField::Get(metaData_);
280    }
281
282    inline void SetFound(bool flag)
283    {
284        IsFoundField::Set(flag, &metaData_);
285    }
286
287    inline bool GetIsInlinedProps() const
288    {
289        return IsInlinedPropsField::Get(metaData_);
290    }
291
292    inline void SetIsInlinedProps(bool flag)
293    {
294        IsInlinedPropsField::Set(flag, &metaData_);
295    }
296
297    inline Representation GetRepresentation() const
298    {
299        return RepresentationField::Get(metaData_);
300    }
301
302    inline void SetRepresentation(Representation representation)
303    {
304        RepresentationField::Set<uint32_t>(representation, &metaData_);
305    }
306
307    inline void SetOffset(uint32_t offset)
308    {
309        OffsetField::Set<uint32_t>(offset, &metaData_);
310    }
311
312    inline uint32_t GetOffset() const
313    {
314        return OffsetField::Get(metaData_);
315    }
316
317private:
318    uint32_t metaData_{0};
319};
320
321class OperationResult {
322public:
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
334    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
343    JSHandle<JSTaggedValue> GetRawValue() const
344    {
345        return value_;
346    }
347
348    const PropertyMetaData &GetPropertyMetaData() const
349    {
350        return metaData_;
351    }
352
353private:
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
363class ECMAObject : public TaggedObject {
364public:
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
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>
397    void VisitObjects(const EcmaObjectRangeVisitor &visitor)
398    {
399        // no field in this object
400        VisitRangeSlot<visitType>(visitor);
401    }
402};
403
404class JSObject : public ECMAObject {
405public:
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
610    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);
771protected:
772    static void ElementsToDictionary(const JSThread *thread, JSHandle<JSObject> obj);
773
774private:
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