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#include "ecmascript/js_object.h"
17#include "ecmascript/dfx/native_module_failure_info.h"
18#include "ecmascript/global_dictionary-inl.h"
19#include "ecmascript/ic/proto_change_details.h"
20#include "ecmascript/interpreter/interpreter.h"
21#include "ecmascript/js_iterator.h"
22#include "ecmascript/js_primitive_ref.h"
23#include "ecmascript/object_fast_operator-inl.h"
24#include "ecmascript/pgo_profiler/pgo_profiler.h"
25#include "ecmascript/property_accessor.h"
26#include "ecmascript/jspandafile/js_pandafile_manager.h"
27
28namespace panda::ecmascript {
29using PGOProfiler = pgo::PGOProfiler;
30PropertyAttributes::PropertyAttributes(const PropertyDescriptor &desc)
31{
32    DISALLOW_GARBAGE_COLLECTION;
33    if (desc.HasWritable()) {
34        SetWritable(desc.IsWritable());
35    }
36
37    if (desc.HasEnumerable()) {
38        SetEnumerable(desc.IsEnumerable());
39    }
40
41    if (desc.HasConfigurable()) {
42        SetConfigurable(desc.IsConfigurable());
43    }
44
45    if (desc.IsAccessorDescriptor()) {
46        SetIsAccessor(true);
47    }
48    // internal accessor
49    if (desc.HasValue() && desc.GetValue()->IsAccessor()) {
50        SetIsAccessor(true);
51    }
52}
53
54void ThroughputJSObjectResizingStrategy::UpdateGrowStep(JSThread *thread, uint32_t step)
55{
56    // 2 : multiple double
57    thread->SetPropertiesGrowStep(std::min(static_cast<uint32_t>(JSObjectResizingStrategy::PROPERTIES_GROW_SIZE * 2),
58                                           step));
59}
60
61Method *ECMAObject::GetCallTarget() const
62{
63    const TaggedObject *obj = this;
64    ASSERT(JSTaggedValue(obj).IsJSFunctionBase() || JSTaggedValue(obj).IsJSProxy());
65
66    JSTaggedValue value;
67    if (JSTaggedValue(obj).IsJSFunctionBase()) {
68        value = JSFunctionBase::ConstCast(obj)->GetMethod();
69    } else {
70        value = JSProxy::ConstCast(obj)->GetMethod();
71    }
72    return Method::Cast(value.GetTaggedObject());
73}
74
75JSHandle<TaggedArray> JSObject::GrowElementsCapacity(const JSThread *thread, const JSHandle<JSObject> &obj,
76                                                     uint32_t capacity, bool highGrowth, bool isNew)
77{
78    uint32_t newCapacity = 0;
79    if (obj->IsJSArray()) {
80        uint32_t hint = JSHandle<JSArray>(obj)->GetHintLength();
81        newCapacity = ComputeElementCapacityWithHint(capacity, hint);
82    }
83    if (obj->IsJSSArray()) {
84        uint32_t hint = JSHandle<JSSharedArray>(obj)->GetHintLength();
85        newCapacity = ComputeElementCapacityWithHint(capacity, hint);
86    }
87    if (newCapacity == 0) {
88        newCapacity = highGrowth ? ComputeElementCapacityHighGrowth(capacity) :
89            ComputeElementCapacity(capacity, isNew);
90    }
91    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
92    JSHandle<TaggedArray> oldElements(thread, obj->GetElements());
93    uint32_t oldLength = oldElements->GetLength();
94
95    ElementsKind kind = obj->GetClass()->GetElementsKind();
96    JSHandle<TaggedArray> newElements =
97        factory->CopyArray(oldElements, oldLength, newCapacity, JSTaggedValue::Hole(),
98                           obj->IsJSShared() ? MemSpaceType::SHARED_OLD_SPACE : MemSpaceType::SEMI_SPACE, kind);
99    obj->SetElements(thread, newElements);
100    if (thread->IsPGOProfilerEnable() && obj->IsJSArray()) {
101        auto trackInfo = JSHandle<JSArray>(obj)->GetTrackInfo();
102        thread->GetEcmaVM()->GetPGOProfiler()->UpdateTrackArrayLength(trackInfo, newCapacity);
103    }
104    return newElements;
105}
106
107JSHandle<JSTaggedValue> JSObject::IterableToList(JSThread *thread, const JSHandle<JSTaggedValue> &items,
108                                                 JSTaggedValue method)
109{
110    // 1. If method is present, then
111    // a. Let iteratorRecord be ? GetIterator(items, sync, method).
112    // 2. Else,
113    // a. Let iteratorRecord be ? GetIterator(items, sync).
114    JSHandle<JSTaggedValue> iteratorRecord;
115    JSHandle<JSTaggedValue> methodHandle(thread, method);
116    if (!methodHandle->IsUndefined()) {
117        iteratorRecord = JSIterator::GetIterator(thread, items, methodHandle);
118        RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
119    } else {
120        iteratorRecord = JSIterator::GetIterator(thread, items);
121        RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
122    }
123    // 3. Let values be a new empty List.
124    // 4. Let next be true.
125    JSHandle<JSArray> array = JSHandle<JSArray>::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
126    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
127    JSHandle<JSTaggedValue> valuesList = JSHandle<JSTaggedValue>::Cast(array);
128    JSMutableHandle<JSTaggedValue> next(thread, JSTaggedValue::True());
129    // 5. Repeat, while next is not false,
130    // a. Set next to ? IteratorStep(iteratorRecord).
131    // b. If next is not false, then
132    // i. Let nextValue be ? IteratorValue(next).
133    // ii. Append nextValue to the end of the List values.
134    uint32_t k = 0;
135    while (!next->IsFalse()) {
136        next.Update(JSIterator::IteratorStep(thread, iteratorRecord).GetTaggedValue());
137        RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
138        if (!next->IsFalse()) {
139            JSHandle<JSTaggedValue> nextValue(JSIterator::IteratorValue(thread, next));
140            RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
141            JSArray::FastSetPropertyByValue(thread, valuesList, k, nextValue);
142            RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
143            k++;
144        }
145    }
146    // 6. Return values.
147    return valuesList;
148}
149
150bool JSObject::IsRegExp(JSThread *thread, const JSHandle<JSTaggedValue> &argument)
151{
152    if (!argument->IsECMAObject()) {
153        return false;
154    }
155    JSHandle<JSTaggedValue> matchSymbol = thread->GetEcmaVM()->GetGlobalEnv()->GetMatchSymbol();
156    JSTaggedValue isRegexp =  ObjectFastOperator::FastGetPropertyByValue(
157        thread, argument.GetTaggedValue(), matchSymbol.GetTaggedValue());
158    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
159    if (!isRegexp.IsUndefined()) {
160        return isRegexp.ToBoolean();
161    }
162    JSHandle<JSObject> argumentObj = JSHandle<JSObject>::Cast(argument);
163    return argumentObj->IsJSRegExp();
164}
165
166JSHandle<NameDictionary> JSObject::TransitionToDictionary(const JSThread *thread, const JSHandle<JSObject> &receiver)
167{
168    JSHandle<TaggedArray> array(thread, receiver->GetProperties());
169    JSHandle<JSHClass> jshclass(thread, receiver->GetJSHClass());
170    ASSERT(!jshclass->IsDictionaryMode());
171    uint32_t propNumber = jshclass->NumberOfProps();
172
173    ASSERT(!jshclass->GetLayout().IsNull());
174    if (jshclass->IsJSShared()) {
175        THROW_TYPE_ERROR_AND_RETURN(const_cast<JSThread *>(thread),
176                                    "shared obj does not support changing or deleting attributes",
177                                    JSHandle<NameDictionary>());
178    }
179    JSHandle<LayoutInfo> layoutInfoHandle(thread, jshclass->GetLayout());
180    JSMutableHandle<NameDictionary> dict(
181        thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(propNumber)));
182    JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
183    JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
184    uint32_t numberInlinedProps = jshclass->GetInlinedProperties();
185    for (uint32_t i = 0; i < propNumber; i++) {
186        JSTaggedValue key = layoutInfoHandle->GetKey(i);
187        PropertyAttributes attr = layoutInfoHandle->GetAttr(i);
188        ASSERT(i == attr.GetOffset());
189        JSTaggedValue value;
190
191        if (i < numberInlinedProps) {
192            value = receiver->GetPropertyInlinedPropsWithRep(i, attr);
193            // If delete a property in hclass which has subtyping info and not prototype, only set value as hole and
194            // not remove. When transition to dictionary, exclude it.
195            if (value.IsHole()) {
196                continue;
197            }
198        } else {
199            value = array->Get(i - numberInlinedProps);
200        }
201
202        attr.SetBoxType(PropertyBoxType::UNDEFINED);
203        valueHandle.Update(value);
204        keyHandle.Update(key);
205        JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
206        dict.Update(newDict);
207    }
208
209    receiver->SetProperties(thread, dict);
210    ElementsKind oldKind = receiver->GetJSHClass()->GetElementsKind();
211    // change HClass
212    JSHClass::TransitionToDictionary(thread, receiver);
213    JSObject::TryMigrateToGenericKindForJSObject(thread, receiver, oldKind);
214
215    // trim in-obj properties space
216    TrimInlinePropsSpace(thread, receiver, numberInlinedProps);
217
218    return dict;
219}
220
221void JSObject::ElementsToDictionary(const JSThread *thread, JSHandle<JSObject> obj)
222{
223    JSHandle<TaggedArray> elements(thread, obj->GetElements());
224    ASSERT(!obj->GetJSHClass()->IsDictionaryElement());
225    uint32_t length = elements->GetLength();
226    if (obj->IsJSShared()) {
227        THROW_TYPE_ERROR(const_cast<JSThread *>(thread),
228                         "shared obj does not support changing or deleting attributes");
229    }
230    JSMutableHandle<NumberDictionary> dict(thread, NumberDictionary::Create(thread));
231    auto attr = PropertyAttributes(PropertyAttributes::GetDefaultAttributes());
232    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
233    JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue ::Undefined());
234    for (uint32_t i = 0; i < length; i++) {
235        JSTaggedValue value = ElementAccessor::Get(obj, i);
236        if (value.IsHole()) {
237            continue;
238        }
239        key.Update(JSTaggedValue(i));
240        valueHandle.Update(value);
241        JSHandle<NumberDictionary> newDict = NumberDictionary::PutIfAbsent(thread, dict, key, valueHandle, attr);
242        dict.Update(newDict);
243    }
244    obj->SetElements(thread, dict);
245
246    ElementsKind oldKind = obj->GetJSHClass()->GetElementsKind();
247    JSHClass::TransitionElementsToDictionary(thread, obj);
248    TryMigrateToGenericKindForJSObject(thread, obj, oldKind);
249}
250
251inline bool JSObject::ShouldOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj)
252{
253    JSHandle<NumberDictionary> elements(thread, obj->GetElements());
254    uint32_t size = static_cast<uint32_t>(elements->Size());
255    for (uint32_t hashIndex = 0; hashIndex < size; hashIndex++) {
256        JSTaggedValue key = elements->GetKey(hashIndex);
257        if (key.IsUndefined() || key.IsHole()) {
258            continue;
259        }
260        PropertyAttributes attr = elements->GetAttributes(hashIndex);
261        if (!attr.IsDefaultAttributes()) {
262            return false;
263        }
264    }
265    return true;
266}
267
268void JSObject::TryOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj)
269{
270    ASSERT(obj->GetJSHClass()->IsDictionaryElement() && obj->IsJSArray());
271    if (ShouldOptimizeAsFastElements(thread, obj)) {
272        uint32_t length = JSArray::Cast(*obj)->GetLength();
273        JSHandle<NumberDictionary> elements(thread, obj->GetElements());
274        uint32_t size = static_cast<uint32_t>(elements->Size());
275        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
276        JSHandle<TaggedArray> array = factory->NewTaggedArray(length);
277        for (uint32_t hashIndex = 0; hashIndex < size; hashIndex++) {
278            JSTaggedValue key = elements->GetKey(hashIndex);
279            JSTaggedValue value = elements->GetValue(hashIndex);
280            if (key.IsUndefined() || key.IsHole()) {
281                continue;
282            }
283            ASSERT(key.IsInt());
284            uint32_t uintKey = static_cast<uint32_t>(key.GetInt());
285            if (uintKey < length) {
286                array->Set(thread, uintKey, value);
287            }
288        }
289        obj->SetElements(thread, array);
290        JSHClass::OptimizeAsFastElements(thread, obj);
291    }
292}
293
294void JSObject::OptimizeAsFastProperties(const JSThread *thread, JSHandle<JSObject> obj)
295{
296    ASSERT(obj->GetJSHClass()->IsDictionaryMode());
297    // 1. Get NameDictionary properties
298    JSHandle<NameDictionary> properties(thread, obj->GetProperties());
299
300    int numberOfProperties = properties->EntriesCount();
301    // Make sure we preserve enough capacity
302    if (numberOfProperties > static_cast<int>(PropertyAttributes::MAX_FAST_PROPS_CAPACITY)) {
303        return ;
304    }
305
306    // 2. iteration indices
307    std::vector<int> indexOrder = properties->GetEnumerationOrder();
308    ASSERT(static_cast<int>(indexOrder.size()) == numberOfProperties);
309
310    // 3. Change Hclass
311    int numberOfInlinedProps = static_cast<int>(obj->GetJSHClass()->GetInlinedProperties());
312    JSHClass::OptimizeAsFastProperties(thread, obj, indexOrder, true);
313
314    // 4. New out-properties
315    int numberOfOutProperties = numberOfProperties - numberOfInlinedProps;
316    ASSERT(numberOfOutProperties >= 0);
317    JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(numberOfOutProperties);
318
319    // 5. Fill properties
320    for (int i = 0; i < numberOfProperties; i++) {
321        JSTaggedValue value = properties->GetValue(indexOrder[i]);
322        if (i < numberOfInlinedProps) {
323            obj->SetPropertyInlinedPropsWithRep(thread, i, value);
324        } else {
325            array->Set(thread, i - numberOfInlinedProps, value);
326        }
327    }
328    obj->SetProperties(thread, array);
329}
330
331void JSObject::SetSProperties(JSThread *thread, JSHandle<JSObject> obj, const std::vector<PropertyDescriptor> &descs)
332{
333    uint32_t length = descs.size();
334    JSMutableHandle<JSTaggedValue> propKey(thread, JSTaggedValue::Undefined());
335    JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
336
337    if (LIKELY(!obj->GetJSHClass()->IsDictionaryMode())) {
338        for (uint32_t i = 0; i < length; ++i) {
339            propValue.Update(descs[i].GetValue());
340            // note(lzl): IsSAccessor?
341            if (!propValue->IsSharedType() && !propValue->IsAccessor()) {
342                THROW_TYPE_ERROR(thread, "The properties of sendable class must be sendable too.");
343            }
344            obj->SetPropertyInlinedProps(thread, i, propValue.GetTaggedValue());
345        }
346    } else {
347        JSMutableHandle<ecmascript::NameDictionary> dict(
348            thread, ecmascript::NameDictionary::CreateInSharedHeap(
349                thread, ecmascript::NameDictionary::ComputeHashTableSize(length)));
350        for (uint32_t i = 0; i < length; i++) {
351            propKey.Update(descs[i].GetKey());
352            propValue.Update(descs[i].GetValue());
353            PropertyAttributes attr =
354                PropertyAttributes::Default(descs[i].IsWritable(), descs[i].IsEnumerable(), descs[i].IsConfigurable());
355            JSHandle<ecmascript::NameDictionary> newDict =
356                ecmascript::NameDictionary::PutIfAbsent(thread, dict, propKey, propValue, attr);
357            dict.Update(newDict);
358        }
359        obj->SetProperties(thread, dict);
360    }
361}
362
363bool JSObject::IsArrayLengthWritable(JSThread *thread, const JSHandle<JSObject> &receiver)
364{
365    auto *hclass = receiver->GetJSHClass();
366    if (!hclass->IsDictionaryMode()) {
367        LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
368        PropertyAttributes attr(layoutInfo->GetAttr(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
369        return attr.IsWritable();
370    }
371    JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
372    ObjectOperator op(thread, receiver, lengthKey, OperatorType::OWN);
373    return op.GetAttr().IsWritable();
374}
375
376bool JSObject::AddElementInternal(JSThread *thread, const JSHandle<JSObject> &receiver,
377                                  uint32_t index, const JSHandle<JSTaggedValue> &value,
378                                  PropertyAttributes attr)
379{
380    ElementsKind kind = ElementsKind::NONE;
381    if (receiver->IsJSArray()) {
382        DISALLOW_GARBAGE_COLLECTION;
383        JSArray *arr = JSArray::Cast(*receiver);
384        uint32_t oldLength = arr->GetArrayLength();
385        if (index >= oldLength) {
386            if (!IsArrayLengthWritable(thread, receiver)) {
387                return false;
388            }
389            arr->SetArrayLength(thread, index + 1);
390            if (index > oldLength) {
391                kind = ElementsKind::HOLE;
392            }
393        }
394    }
395    if (receiver->IsJSSArray()) {
396        DISALLOW_GARBAGE_COLLECTION;
397        JSSharedArray *arr = JSSharedArray::Cast(*receiver);
398        uint32_t oldLength = arr->GetArrayLength();
399        if (index >= oldLength) {
400            JSHandle<JSTaggedValue> newLength(thread, JSTaggedValue(static_cast<uint32_t>(index + 1)));
401            JSSharedArray::LengthSetter(thread, receiver, newLength);
402            if (index > oldLength) {
403                kind = ElementsKind::HOLE;
404            }
405        }
406    }
407    thread->NotifyStableArrayElementsGuardians(receiver, StableArrayChangeKind::NOT_PROTO);
408
409    // check whether to convert to dictionary
410    if (receiver->GetJSHClass()->IsDictionaryElement() && receiver->IsJSArray()) {
411        JSArray *arr = JSArray::Cast(*receiver);
412        uint32_t capacity = arr->GetArrayLength();
413        TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
414        ASSERT(elements->IsDictionaryMode());
415        if (ShouldTransToFastElements(thread, elements, capacity, index)) {
416            JSObject::TryOptimizeAsFastElements(thread, receiver);
417        }
418    }
419
420    bool isDictionary = receiver->GetJSHClass()->IsDictionaryElement();
421    TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
422    if (isDictionary) {
423        ASSERT(elements->IsDictionaryMode());
424        JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(static_cast<int32_t>(index)));
425        JSHandle<NumberDictionary> newDict =
426            NumberDictionary::Put(thread, JSHandle<NumberDictionary>(thread, elements), keyHandle, value, attr);
427        receiver->SetElements(thread, newDict);
428        return true;
429    }
430
431    uint32_t capacity = elements->GetLength();
432    if (index >= capacity || !attr.IsDefaultAttributes()) {
433        if (!receiver->IsJSSArray() && (ShouldTransToDict(capacity, index) || !attr.IsDefaultAttributes())) {
434            JSObject::ElementsToDictionary(thread, receiver);
435            RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
436            JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(static_cast<int32_t>(index)));
437            JSHandle<NumberDictionary> dict(thread, receiver->GetElements());
438            JSHandle<NumberDictionary> newKey = NumberDictionary::Put(thread, dict, keyHandle, value, attr);
439            receiver->SetElements(thread, newKey);
440            return true;
441        }
442        elements = *JSObject::GrowElementsCapacity(thread, receiver, index + 1);
443    }
444    bool needTransition = true;
445    if (receiver->IsJSShared()) {
446        needTransition = false;
447    }
448    ElementAccessor::Set(thread, receiver, index, value, needTransition, kind);
449    return true;
450}
451
452void JSObject::DeletePropertyInternal(JSThread *thread, const JSHandle<JSObject> &obj,
453                                      const JSHandle<JSTaggedValue> &key, uint32_t index)
454{
455    JSHandle<TaggedArray> array(thread, obj->GetProperties());
456
457    if (obj->IsJSGlobalObject()) {
458        JSHandle<GlobalDictionary> dictHandle(thread, obj->GetProperties());
459        PropertyBox* box = dictHandle->GetBox(index);
460        box->Clear(thread);
461        JSHandle<GlobalDictionary> newDict = GlobalDictionary::Remove(thread, dictHandle, index);
462        obj->SetProperties(thread, newDict);
463        return;
464    }
465
466    if (!array->IsDictionaryMode()) {
467        JSHandle<NameDictionary> dictHandle(TransitionToDictionary(thread, obj));
468        RETURN_IF_ABRUPT_COMPLETION(thread);
469        int entry = dictHandle->FindEntry(key.GetTaggedValue());
470        ASSERT(entry != -1);
471        JSHandle<NameDictionary> newDict = NameDictionary::Remove(thread, dictHandle, entry);
472        obj->SetProperties(thread, newDict);
473        return;
474    }
475
476    JSHandle<NameDictionary> dictHandle(array);
477    JSHandle<NameDictionary> newDict = NameDictionary::Remove(thread, dictHandle, index);
478    obj->SetProperties(thread, newDict);
479}
480
481void JSObject::GetAllKeys(const JSThread *thread, const JSHandle<JSObject> &obj, int offset,
482                          const JSHandle<TaggedArray> &keyArray)
483
484{
485    TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
486    if (!array->IsDictionaryMode()) {
487        int end = static_cast<int>(obj->GetJSHClass()->NumberOfProps());
488        if (end > 0) {
489            LayoutInfo::Cast(obj->GetJSHClass()->GetLayout().GetTaggedObject())
490                ->GetAllKeys(thread, end, offset, *keyArray, obj);
491        }
492        return;
493    }
494
495    if (obj->IsJSGlobalObject()) {
496        GlobalDictionary *dict = GlobalDictionary::Cast(array);
497        return dict->GetAllKeys(thread, offset, *keyArray);
498    }
499
500    NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
501    dict->GetAllKeys(thread, offset, *keyArray);
502}
503
504void JSObject::GetAllKeysByFilter(const JSThread *thread, const JSHandle<JSObject> &obj,
505                                  uint32_t &keyArrayEffectivelength,
506                                  const JSHandle<TaggedArray> &keyArray,
507                                  uint32_t filter)
508{
509    TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
510    if (!array->IsDictionaryMode()) {
511        uint32_t numberOfProps = obj->GetJSHClass()->NumberOfProps();
512        if (numberOfProps > 0) {
513            LayoutInfo::Cast(obj->GetJSHClass()->GetLayout().GetTaggedObject())->
514                GetAllKeysByFilter(thread, numberOfProps, keyArrayEffectivelength, *keyArray, obj, filter);
515        }
516        return;
517    }
518
519    if (obj->IsJSGlobalObject()) {
520        GlobalDictionary *dict = GlobalDictionary::Cast(array);
521        return dict->GetAllKeysByFilter(thread, keyArrayEffectivelength, *keyArray, filter);
522    }
523
524    NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
525    dict->GetAllKeysByFilter(thread, keyArrayEffectivelength, *keyArray, filter);
526}
527
528// For Serialization use. Does not support JSGlobalObject
529void JSObject::GetAllKeysForSerialization(const JSHandle<JSObject> &obj, std::vector<JSTaggedValue> &keyVector)
530{
531    DISALLOW_GARBAGE_COLLECTION;
532    ASSERT_PRINT(!obj->IsJSGlobalObject(), "Do not support get key of JSGlobal Object");
533    TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
534    if (!array->IsDictionaryMode()) {
535        int end = static_cast<int>(obj->GetJSHClass()->NumberOfProps());
536        if (end > 0) {
537            LayoutInfo::Cast(obj->GetJSHClass()->GetLayout().GetTaggedObject())->GetAllKeysForSerialization(end,
538                keyVector);
539        }
540    } else {
541        NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
542        dict->GetAllKeysIntoVector(keyVector);
543    }
544}
545
546JSHandle<TaggedArray> JSObject::GetAllEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj,
547                                               uint32_t numOfKeys, uint32_t *keys)
548{
549    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
550    if (obj->IsJSGlobalObject()) {
551        JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(numOfKeys);
552        GlobalDictionary *dict = GlobalDictionary::Cast(obj->GetProperties().GetTaggedObject());
553        dict->GetEnumAllKeys(thread, 0, *keyArray, keys);
554        return keyArray;
555    }
556
557    TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
558    if (!array->IsDictionaryMode()) {
559        JSHClass *jsHclass = obj->GetJSHClass();
560        JSTaggedValue enumCache = jsHclass->GetEnumCache();
561        if (JSObject::GetEnumCacheKind(thread, enumCache) == EnumCacheKind::ONLY_OWN_KEYS) {
562            JSHandle<TaggedArray> cacheArray = JSHandle<TaggedArray>(thread, enumCache);
563            JSHandle<TaggedArray> keyArray = factory->CopyFromEnumCache(cacheArray);
564            *keys = keyArray->GetLength();
565            return keyArray;
566        }
567
568        if (numOfKeys > 0) {
569            int end = static_cast<int>(jsHclass->NumberOfProps());
570            JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(numOfKeys + EnumCache::ENUM_CACHE_HEADER_SIZE);
571            LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject())
572                ->GetAllEnumKeys(thread, end, EnumCache::ENUM_CACHE_HEADER_SIZE, keyArray, keys, obj);
573            JSObject::SetEnumCacheKind(thread, *keyArray, EnumCacheKind::ONLY_OWN_KEYS);
574            if (!JSTaggedValue(jsHclass).IsInSharedHeap()) {
575                jsHclass->SetEnumCache(thread, keyArray.GetTaggedValue());
576            }
577            JSHandle<TaggedArray> newkeyArray = factory->CopyFromEnumCache(keyArray);
578            return newkeyArray;
579        }
580        return factory->EmptyArray();
581    }
582
583    JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(numOfKeys);
584    NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
585    dict->GetAllEnumKeys(thread, 0, keyArray, keys);
586    return keyArray;
587}
588
589uint32_t JSObject::GetAllEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
590                                  const JSHandle<TaggedArray> &keyArray)
591{
592    TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
593    uint32_t keys = 0;
594    if (!array->IsDictionaryMode()) {
595        JSHClass *jsHclass = obj->GetJSHClass();
596        int end = static_cast<int>(jsHclass->NumberOfProps());
597        if (end > 0) {
598            LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject())
599                ->GetAllEnumKeys(thread, end, offset, keyArray, &keys, obj);
600        }
601        return keys;
602    }
603    if (obj->IsJSGlobalObject()) {
604        GlobalDictionary *dict = GlobalDictionary::Cast(obj->GetProperties().GetTaggedObject());
605        dict->GetEnumAllKeys(thread, offset, *keyArray, &keys);
606        return keys;
607    }
608
609    NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
610    dict->GetAllEnumKeys(thread, offset, keyArray, &keys);
611    return keys;
612}
613
614void JSObject::GetAllElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
615                                 const JSHandle<TaggedArray> &keyArray)
616{
617    uint32_t elementIndex = 0;
618    if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
619        elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength() + static_cast<uint32_t>(offset);
620        for (uint32_t i = static_cast<uint32_t>(offset); i < elementIndex; ++i) {
621            auto key = base::NumberHelper::IntToEcmaString(thread, i);
622            keyArray->Set(thread, i, key);
623        }
624    }
625
626    if (!ElementAccessor::IsDictionaryMode(obj)) {
627        uint32_t elementsLen = ElementAccessor::GetElementsLength(obj);
628        for (uint32_t i = 0, j = elementIndex; i < elementsLen; ++i) {
629            if (!ElementAccessor::Get(obj, i).IsHole()) {
630                auto key = base::NumberHelper::IntToEcmaString(thread, i);
631                keyArray->Set(thread, j++, key);
632            }
633        }
634    } else {
635        JSHandle<TaggedArray> elements(thread, obj->GetElements());
636        NumberDictionary::GetAllKeys(thread, JSHandle<NumberDictionary>(elements), elementIndex, keyArray);
637    }
638}
639
640void JSObject::GetAllElementKeysByFilter(JSThread *thread,
641                                         const JSHandle<JSObject> &obj,
642                                         const JSHandle<TaggedArray> &keyArray,
643                                         uint32_t &keyArrayEffectiveLength,
644                                         uint32_t filter)
645{
646    ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
647    uint32_t elementIndex = 0;
648
649    // For strings attributes, only enumerable is true
650    if ((filter & NATIVE_ENUMERABLE) && obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
651        elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength();
652        for (uint32_t i = 0; i < elementIndex; ++i) {
653            keyArray->Set(thread, keyArrayEffectiveLength, JSTaggedValue(i));
654            keyArrayEffectiveLength++;
655        }
656    }
657
658    JSHandle<JSTaggedValue> objValue(obj);
659
660    if (!ElementAccessor::IsDictionaryMode(obj)) {
661        uint32_t elementsLen = ElementAccessor::GetElementsLength(obj);
662        for (uint32_t i = 0; i < elementsLen; ++i) {
663            if (!ElementAccessor::Get(obj, i).IsHole()) {
664                ObjectOperator op(thread, objValue, i, OperatorType::OWN);
665                bool bIgnore = FilterHelper::IgnoreKeyByFilter<ObjectOperator>(op, filter);
666                if (bIgnore) {
667                    continue;
668                }
669                keyArray->Set(thread, keyArrayEffectiveLength, JSTaggedValue(i));
670                keyArrayEffectiveLength++;
671            }
672        }
673    } else {
674        JSHandle<TaggedArray> elements(thread, obj->GetElements());
675        NumberDictionary::GetAllKeysByFilter(thread, JSHandle<NumberDictionary>(elements),
676            keyArrayEffectiveLength, keyArray, filter);
677    }
678}
679
680void JSObject::GetALLElementKeysIntoVector(const JSThread *thread, const JSHandle<JSObject> &obj,
681                                           std::vector<JSTaggedValue> &keyVector)
682{
683    if (!ElementAccessor::IsDictionaryMode(obj)) {
684        uint32_t elementsLen = ElementAccessor::GetElementsLength(obj);
685        for (uint32_t i = 0; i < elementsLen; ++i) {
686            if (!ElementAccessor::Get(obj, i).IsHole()) {
687                keyVector.emplace_back(JSTaggedValue(i));
688            }
689        }
690    } else {
691        JSHandle<TaggedArray> elements(thread, obj->GetElements());
692        JSHandle<NumberDictionary> dict = JSHandle<NumberDictionary>::Cast(elements);
693        dict->GetAllKeysIntoVector(keyVector);
694    }
695}
696
697JSHandle<TaggedArray> JSObject::GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
698                                                   uint32_t numOfElements, uint32_t *keys)
699{
700    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
701    JSHandle<TaggedArray> elementArray = factory->NewTaggedArray(numOfElements);
702    CollectEnumElementsAlongProtoChain(thread, obj, offset, elementArray, keys);
703    return elementArray;
704}
705
706void JSObject::CollectEnumElementsAlongProtoChain(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
707                                                  JSHandle<TaggedArray> elementArray, uint32_t *keys,
708                                                  int32_t lastLength)
709{
710    uint32_t elementIndex = static_cast<uint32_t>(offset);
711    JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
712
713    if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
714        uint32_t strLen = JSPrimitiveRef::Cast(*obj)->GetStringLength();
715        for (uint32_t i = 0; i < strLen; ++i) {
716            keyHandle.Update(base::NumberHelper::IntToEcmaString(thread, i));
717            elementArray->Set(thread, elementIndex, keyHandle);
718            elementIndex++;
719        }
720        *keys += strLen;
721    }
722
723    if (!ElementAccessor::IsDictionaryMode(obj)) {
724        JSHandle<TaggedQueue> emptyQueue = thread->GetEcmaVM()->GetFactory()->GetEmptyTaggedQueue();
725        uint32_t elementsLen = ElementAccessor::GetElementsLength(obj);
726        uint32_t preElementIndex = elementIndex;
727        for (uint32_t i = 0; i < elementsLen; ++i) {
728            if (ElementAccessor::Get(obj, i).IsHole()) {
729                continue;
730            }
731            keyHandle.Update(base::NumberHelper::IntToEcmaString(thread, i));
732            bool isDuplicated = IsDepulicateKeys(thread, elementArray, lastLength, emptyQueue, keyHandle);
733            if (isDuplicated) {
734                continue;
735            }
736            elementArray->Set(thread, elementIndex, keyHandle);
737            elementIndex++;
738        }
739        *keys += (elementIndex - preElementIndex);
740    } else {
741        JSHandle<TaggedArray> arr(thread, obj->GetElements());
742        NumberDictionary::GetAllEnumKeys(
743            thread, JSHandle<NumberDictionary>(arr), elementIndex, elementArray, keys, lastLength);
744    }
745}
746
747void JSObject::GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
748                                  const JSHandle<TaggedArray> &keyArray)
749{
750    uint32_t elementIndex = 0;
751    if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
752        elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength() + static_cast<uint32_t>(offset);
753        for (uint32_t i = static_cast<uint32_t>(offset); i < elementIndex; ++i) {
754            auto key = base::NumberHelper::IntToEcmaString(thread, i);
755            keyArray->Set(thread, i, key);
756        }
757    }
758
759    if (!ElementAccessor::IsDictionaryMode(obj)) {
760        uint32_t elementsLen = ElementAccessor::GetElementsLength(obj);
761        for (uint32_t i = 0, j = elementIndex; i < elementsLen; ++i) {
762            if (!ElementAccessor::Get(obj, i).IsHole()) {
763                auto key = base::NumberHelper::IntToEcmaString(thread, i);
764                keyArray->Set(thread, j++, key);
765            }
766        }
767    } else {
768        JSHandle<TaggedArray> elements(thread, obj->GetElements());
769        uint32_t keys = 0;
770        NumberDictionary::GetAllEnumKeys(thread, JSHandle<NumberDictionary>(elements), elementIndex, keyArray, &keys);
771    }
772}
773
774std::pair<uint32_t, uint32_t> JSObject::GetNumberOfEnumKeys() const
775{
776    DISALLOW_GARBAGE_COLLECTION;
777    TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
778    if (!array->IsDictionaryMode()) {
779        int end = static_cast<int>(GetJSHClass()->NumberOfProps());
780        if (end > 0) {
781            LayoutInfo *layout = LayoutInfo::Cast(GetJSHClass()->GetLayout().GetTaggedObject());
782            return layout->GetNumOfEnumKeys(end, this);
783        }
784        return std::make_pair(0, 0);
785    }
786    if (IsJSGlobalObject()) {
787        GlobalDictionary *dict = GlobalDictionary::Cast(array);
788        return dict->GetNumOfEnumKeys();
789    }
790
791    NameDictionary *dict = NameDictionary::Cast(GetProperties().GetTaggedObject());
792    return dict->GetNumOfEnumKeys();
793}
794
795uint32_t JSObject::GetNumberOfKeys()
796{
797    DISALLOW_GARBAGE_COLLECTION;
798    TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
799
800    if (!array->IsDictionaryMode()) {
801        return GetJSHClass()->NumberOfProps();
802    }
803
804    return NameDictionary::Cast(array)->EntriesCount();
805}
806
807bool JSObject::GlobalSetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key,
808                                 const JSHandle<JSTaggedValue> &value, bool mayThrow)
809{
810    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
811
812    ObjectOperator op(thread, key);
813    if (!op.IsFound()) {
814        PropertyAttributes attr = PropertyAttributes::Default(true, true, false);
815        op.SetAttr(attr);
816    }
817    return SetProperty(&op, value, mayThrow);
818}
819
820uint32_t JSObject::GetNumberOfElements()
821{
822    DISALLOW_GARBAGE_COLLECTION;
823    uint32_t numOfElements = 0;
824    if (IsJSPrimitiveRef() && JSPrimitiveRef::Cast(this)->IsString()) {
825        numOfElements = JSPrimitiveRef::Cast(this)->GetStringLength();
826    }
827
828    if (!ElementAccessor::IsDictionaryMode(this)) {
829        uint32_t elementsLen = ElementAccessor::GetElementsLength(this);
830        for (uint32_t i = 0; i < elementsLen; ++i) {
831            if (!ElementAccessor::Get(this, i).IsHole()) {
832                numOfElements++;
833            }
834        }
835    } else {
836        TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
837        numOfElements += static_cast<uint32_t>(NumberDictionary::Cast(elements)->EntriesCount());
838    }
839
840    return numOfElements;
841}
842
843// 9.1.9 [[Set]] ( P, V, Receiver)
844bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
845                           const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
846{
847    ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
848    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
849
850    // 2 ~ 4 findProperty in Receiver, Obj and its parents
851    ObjectOperator op(thread, obj, receiver, key);
852    return SetProperty(&op, value, mayThrow);
853}
854
855bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
856                           const JSHandle<JSTaggedValue> &value, bool mayThrow)
857{
858    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid JSObject");
859    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
860
861    ObjectOperator op(thread, obj, key);
862    return SetProperty(&op, value, mayThrow);
863}
864
865bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
866                           const JSHandle<JSTaggedValue> &value, bool mayThrow, SCheckMode sCheckMode)
867{
868    ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
869    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
870
871    if (obj->IsJSSharedArray()) {
872        return JSSharedArray::SetProperty(thread, obj, key, value, mayThrow, sCheckMode);
873    }
874    // 2 ~ 4 findProperty in Receiver, Obj and its parents
875    ObjectOperator op(thread, obj, key);
876    return SetProperty(&op, value, mayThrow);
877}
878
879bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index,
880                           const JSHandle<JSTaggedValue> &value, bool mayThrow)
881{
882    ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
883
884    ObjectOperator op(thread, obj, index);
885    return SetProperty(&op, value, mayThrow);
886}
887
888bool JSObject::SetPropertyForDataDescriptorProxy(JSThread *thread, ObjectOperator *op,
889                                                 const JSHandle<JSTaggedValue> &value,
890                                                 JSHandle<JSTaggedValue> &receiver)
891{
892    ASSERT(receiver->IsJSProxy());
893    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
894    if (op->IsElement()) {
895        key.Update(JSTaggedValue(op->GetElementIndex()));
896    } else {
897        key.Update(op->GetKey().GetTaggedValue());
898    }
899
900    PropertyDescriptor existDesc(thread);
901    JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>::Cast(receiver), key, existDesc);
902    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
903    if (!existDesc.IsEmpty()) {
904        if (existDesc.IsAccessorDescriptor()) {
905            return false;
906        }
907
908        if (!existDesc.IsWritable()) {
909            return false;
910        }
911
912        PropertyDescriptor valueDesc(thread, value);
913        return JSProxy::DefineOwnProperty(thread, JSHandle<JSProxy>::Cast(receiver), key, valueDesc);
914    }
915    return CreateDataProperty(thread, JSHandle<JSObject>(receiver), key, value);
916}
917
918bool JSObject::SetPropertyForDataDescriptor(ObjectOperator *op, const JSHandle<JSTaggedValue> &value,
919                                            JSHandle<JSTaggedValue> &receiver, bool mayThrow, bool isInternalAccessor)
920{
921    JSThread *thread = op->GetThread();
922    if (!op->IsWritable()) {
923        if (mayThrow) {
924            THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetReadOnlyProperty), false);
925        }
926        return false;
927    }
928
929    if (!receiver->IsECMAObject()) {
930        if (mayThrow) {
931            THROW_TYPE_ERROR_AND_RETURN(thread, "Receiver is not a JSObject", false);
932        }
933        return false;
934    }
935    if (op->IsFound() && receiver->IsJSShared()) {
936        if (!ClassHelper::MatchFieldType(op->GetSharedFieldType(), value.GetTaggedValue())) {
937            if (mayThrow) {
938                THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), false);
939            }
940            return false;
941        }
942    }
943
944    if (receiver->IsJSProxy()) {
945        return SetPropertyForDataDescriptorProxy(thread, op, value, receiver);
946    }
947
948    // 5e. If existingDescriptor is not undefined, then
949    bool hasReceiver = false;
950    if (op->HasReceiver()) {
951        op->ReLookupPropertyInReceiver();
952        isInternalAccessor = false;
953        if (op->IsAccessorDescriptor()) {
954            JSTaggedValue ret = ShouldGetValueFromBox(op);
955            isInternalAccessor = AccessorData::Cast(ret.GetTaggedObject())->IsInternal();
956        }
957        hasReceiver = true;
958    }
959    bool isSuccess = true;
960    if (op->IsFound() && !op->IsOnPrototype()) {
961        // i. If IsAccessorDescriptor(existingDescriptor) is true, return false.
962        if (op->IsAccessorDescriptor() && !isInternalAccessor) {
963            return false;
964        }
965
966        // ii. If existingDescriptor.[[Writable]] is false, return false.
967        if (!op->IsWritable()) {
968            if (mayThrow) {
969                THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetReadOnlyProperty), false);
970            }
971            return false;
972        }
973        if (hasReceiver && receiver->IsJSShared() &&
974            !ClassHelper::MatchFieldType(op->GetSharedFieldType(), value.GetTaggedValue())) {
975            if (mayThrow) {
976                THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), false);
977            }
978            return false;
979        }
980        isSuccess = op->UpdateDataValue(JSHandle<JSObject>(receiver), value, isInternalAccessor, mayThrow);
981        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, isSuccess);
982    } else {
983        // 5f. Else if Receiver does not currently have a property P, Return CreateDataProperty(Receiver, P, V).
984        // fixme(hzzhouzebin) this makes SharedArray's frozen no sense.
985        if (!receiver->IsExtensible(thread) && !(receiver->IsJSSharedArray() && op->IsElement())) {
986            if (mayThrow) {
987                THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetPropertyWhenNotExtensible), false);
988            }
989            return false;
990        }
991        if (hasReceiver || isInternalAccessor) {
992            return op->AddProperty(JSHandle<JSObject>(receiver), value, PropertyAttributes::Default());
993        } else if (op->IsFound() && receiver.GetTaggedValue() != op->GetHolder().GetTaggedValue()) {
994            return op->AddProperty(JSHandle<JSObject>(receiver), value, PropertyAttributes::Default());
995        } else {
996            return op->AddProperty(JSHandle<JSObject>(receiver), value, op->GetAttr());
997        }
998    }
999    return isSuccess;
1000}
1001
1002bool JSObject::SetProperty(ObjectOperator *op, const JSHandle<JSTaggedValue> &value, bool mayThrow)
1003{
1004    JSThread *thread = op->GetThread();
1005    op->UpdateDetector();
1006
1007    JSHandle<JSTaggedValue> receiver = op->GetReceiver();
1008    JSHandle<JSTaggedValue> holder = op->GetHolder();
1009    if (holder->IsJSProxy()) {
1010        if (op->IsElement()) {
1011            JSHandle<JSTaggedValue> key(thread, JSTaggedValue(op->GetElementIndex()));
1012            return JSProxy::SetProperty(thread, JSHandle<JSProxy>::Cast(holder), key, value, receiver, mayThrow);
1013        }
1014        return JSProxy::SetProperty(thread, JSHandle<JSProxy>::Cast(holder), op->GetKey(), value, receiver, mayThrow);
1015    }
1016
1017    // When op is not found and is not set extra attributes
1018    if (!op->IsFound() && op->IsPrimitiveAttr()) {
1019        op->SetAsDefaultAttr();
1020    }
1021
1022    bool isInternalAccessor = false;
1023    if (op->IsAccessorDescriptor()) {
1024        JSTaggedValue ret = ShouldGetValueFromBox(op);
1025        isInternalAccessor = AccessorData::Cast(ret.GetTaggedObject())->IsInternal();
1026    }
1027
1028    // 5. If IsDataDescriptor(ownDesc) is true, then
1029    if (!op->IsAccessorDescriptor() || isInternalAccessor) {
1030        return SetPropertyForDataDescriptor(op, value, receiver, mayThrow, isInternalAccessor);
1031    }
1032    // 6. Assert: IsAccessorDescriptor(ownDesc) is true.
1033    ASSERT(op->IsAccessorDescriptor());
1034    // 8. If setter is undefined, return false.
1035    JSTaggedValue ret = ShouldGetValueFromBox(op);
1036    AccessorData *accessor = AccessorData::Cast(ret.GetTaggedObject());
1037    return CallSetter(thread, *accessor, receiver, value, mayThrow);
1038}
1039
1040bool JSObject::CallSetter(JSThread *thread, const AccessorData &accessor, const JSHandle<JSTaggedValue> &receiver,
1041                          const JSHandle<JSTaggedValue> &value, bool mayThrow)
1042{
1043    if (UNLIKELY(accessor.IsInternal())) {
1044        return accessor.CallInternalSet(thread, JSHandle<JSObject>::Cast(receiver), value, mayThrow);
1045    }
1046    JSTaggedValue setter = accessor.GetSetter();
1047    // 8. If setter is undefined, return false.
1048    if (setter.IsUndefined()) {
1049        if (mayThrow) {
1050            THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property when setter is undefined", false);
1051        }
1052        return false;
1053    }
1054
1055    JSHandle<JSTaggedValue> func(thread, setter);
1056    JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1057    EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, receiver, undefined, 1);
1058    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1059    info->SetCallArg(value.GetTaggedValue());
1060    JSFunction::Call(info);
1061
1062    // 10. ReturnIfAbrupt(setterResult).
1063    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1064
1065    return true;
1066}
1067
1068JSTaggedValue JSObject::CallGetter(JSThread *thread, const AccessorData *accessor,
1069                                   const JSHandle<JSTaggedValue> &receiver)
1070{
1071    JSTaggedValue getter = accessor->GetGetter();
1072    // 7. If getter is undefined, return undefined.
1073    if (getter.IsUndefined()) {
1074        return JSTaggedValue::Undefined();
1075    }
1076
1077    JSHandle<JSTaggedValue> func(thread, getter);
1078    JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1079    EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, receiver, undefined, 0);
1080    JSTaggedValue res = JSFunction::Call(info);
1081    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1082    return res;
1083}
1084
1085// 9.1.8 [[Get]] (P, Receiver)
1086OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1087                                      const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
1088{
1089    ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
1090    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1091
1092    ObjectOperator op(thread, obj, receiver, key);
1093    return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
1094}
1095
1096OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSObject> &obj,
1097                                      const JSHandle<JSTaggedValue> &key)
1098{
1099    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid JSObject");
1100    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1101
1102    ObjectOperator op(thread, obj, key);
1103    return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
1104}
1105
1106OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1107                                      const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode)
1108{
1109    ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
1110    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1111    if (obj->IsJSSharedArray()) {
1112        return JSSharedArray::GetProperty(thread, obj, key, sCheckMode);
1113    }
1114    ObjectOperator op(thread, obj, key);
1115    return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
1116}
1117
1118OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index)
1119{
1120    ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
1121
1122    ObjectOperator op(thread, obj, index);
1123    return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
1124}
1125
1126OperationResult JSObject::GetPropertyFromGlobal(JSThread *thread, const JSHandle<JSTaggedValue> &key)
1127{
1128    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1129
1130    ObjectOperator op(thread, key);
1131    return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
1132}
1133
1134PropertyBox* JSObject::GetGlobalPropertyBox(JSTaggedValue key)
1135{
1136    ASSERT(IsJSGlobalObject());
1137    auto dict = GlobalDictionary::Cast(GetProperties().GetTaggedObject());
1138    auto entry = dict->FindEntry(key);
1139    if (entry == -1) {
1140        return nullptr;
1141    }
1142    return dict->GetBox(entry);
1143}
1144
1145PropertyBox* JSObject::GetGlobalPropertyBox(JSThread *thread, const std::string& key)
1146{
1147    auto factory = thread->GetEcmaVM()->GetFactory();
1148    auto keyValue = factory->NewFromUtf8(key).GetTaggedValue();
1149    return GetGlobalPropertyBox(keyValue);
1150}
1151
1152JSTaggedValue JSObject::GetProperty(JSThread *thread, ObjectOperator *op)
1153{
1154    JSHandle<JSTaggedValue> receiver = op->GetReceiver();
1155    JSHandle<JSTaggedValue> holder = op->GetHolder();
1156    if (receiver->IsNativeModuleFailureInfo()) {
1157        JSTaggedValue failureInfo = JSHandle<NativeModuleFailureInfo>::Cast(receiver)->GetArkNativeModuleFailureInfo();
1158        THROW_REFERENCE_ERROR_AND_RETURN(thread, ConvertToString(failureInfo).c_str(), JSTaggedValue::Undefined());
1159    }
1160    if (holder->IsJSProxy()) {
1161        if (op->IsElement()) {
1162            JSHandle<JSTaggedValue> key(thread, JSTaggedValue(op->GetElementIndex()));
1163            return JSProxy::GetProperty(thread, JSHandle<JSProxy>::Cast(holder), key, receiver)
1164                .GetValue()
1165                .GetTaggedValue();
1166        }
1167        return JSProxy::GetProperty(thread, JSHandle<JSProxy>::Cast(holder), op->GetKey(), receiver)
1168            .GetValue()
1169            .GetTaggedValue();
1170    }
1171
1172    // 4. If desc is undefined, then
1173    if (!op->IsFound()) {
1174        // 4c. If obj and parent is null, return undefined.
1175        return JSTaggedValue::Undefined();
1176    }
1177    // 5. If IsDataDescriptor(desc) is true, return desc.[[Value]]
1178    JSTaggedValue ret = ShouldGetValueFromBox(op);
1179    if (!op->IsAccessorDescriptor()) {
1180        return ret;
1181    }
1182
1183    // 6. Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].
1184    AccessorData *accessor = AccessorData::Cast(ret.GetTaggedObject());
1185    // 8. Return Call(getter, Receiver).
1186    if (UNLIKELY(accessor->IsInternal())) {
1187        return accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(holder));
1188    }
1189    return CallGetter(thread, accessor, receiver);
1190}
1191
1192bool JSObject::DeleteProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1193                              SCheckMode sCheckMode)
1194{
1195    // 1. Assert: IsPropertyKey(P) is true.
1196    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1197    // 2. Let desc be O.[[GetOwnProperty]](P).
1198    ObjectOperator op(thread, JSHandle<JSTaggedValue>(obj), key, OperatorType::OWN);
1199
1200    // 4. If desc is undefined, return true.
1201    if (!op.IsFound()) {
1202        return true;
1203    }
1204    // 5. If desc.[[Configurable]] is true, then
1205    // a. Remove the own property with name P from O.
1206    // b. Return true.
1207    // 6. Return false.
1208    if (op.IsConfigurable() || sCheckMode == SCheckMode::SKIP) {
1209        op.DeletePropertyInHolder();
1210        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1211        obj->GetClass()->SetHasDeleteProperty(true);
1212        return true;
1213    }
1214    return false;
1215}
1216
1217bool JSObject::GetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1218                              PropertyDescriptor &desc)
1219{
1220    return OrdinaryGetOwnProperty(thread, obj, key, desc);
1221}
1222
1223bool JSObject::GlobalGetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1224{
1225    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1226    ObjectOperator op(thread, key, OperatorType::OWN);
1227
1228    if (!op.IsFound()) {
1229        return false;
1230    }
1231
1232    op.ToPropertyDescriptor(desc);
1233
1234    if (desc.HasValue()) {
1235        PropertyBox *cell = PropertyBox::Cast(desc.GetValue().GetTaggedValue().GetTaggedObject());
1236        JSHandle<JSTaggedValue> valueHandle(thread, cell->GetValue());
1237        desc.SetValue(valueHandle);
1238    }
1239    ASSERT(!desc.GetValue()->IsInternalAccessor());
1240    return true;
1241}
1242
1243bool JSObject::OrdinaryGetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
1244                                      const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1245{
1246    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1247    ObjectOperator op(thread, JSHandle<JSTaggedValue>(obj), key, OperatorType::OWN);
1248
1249    if (!op.IsFound()) {
1250        return false;
1251    }
1252
1253    op.ToPropertyDescriptor(desc);
1254
1255    if (desc.HasValue() && obj->IsJSGlobalObject()) {
1256        JSTaggedValue val = desc.GetValue().GetTaggedValue();
1257        if (val.IsPropertyBox()) {
1258            PropertyBox *cell = PropertyBox::Cast(val.GetTaggedObject());
1259            JSHandle<JSTaggedValue> valueHandle(thread, cell->GetValue());
1260            desc.SetValue(valueHandle);
1261        }
1262    }
1263
1264    return true;
1265}
1266
1267bool JSObject::DefineOwnProperty(JSThread *thread, ObjectOperator *op,
1268                                 const PropertyDescriptor &desc, SCheckMode sCheckMode)
1269{
1270    return OrdinaryDefineOwnProperty(thread, op, desc, sCheckMode);
1271}
1272
1273bool JSObject::DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1274                                 const PropertyDescriptor &desc, SCheckMode sCheckMode)
1275{
1276    return OrdinaryDefineOwnProperty(thread, obj, key, desc, sCheckMode);
1277}
1278
1279bool JSObject::DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1280                                 const PropertyDescriptor &desc, SCheckMode sCheckMode)
1281{
1282    return OrdinaryDefineOwnProperty(thread, obj, index, desc, sCheckMode);
1283}
1284
1285// 9.1.6.1 OrdinaryDefineOwnProperty (O, P, Desc)
1286bool JSObject::OrdinaryDefineOwnProperty(JSThread *thread, ObjectOperator *op,
1287                                         const PropertyDescriptor &desc, SCheckMode sCheckMode)
1288{
1289    auto obj = JSHandle<JSObject>::Cast(op->GetHolder());
1290    bool extensible = obj->IsExtensible();
1291    // make extensible for shared array to add element.
1292    if (obj->IsJSSArray() && op->IsElement()) {
1293        extensible = true;
1294    }
1295    PropertyDescriptor current(thread);
1296    op->ToPropertyDescriptor(current);
1297    // 4. Return ValidateAndApplyPropertyDescriptor(O, P, extensible, Desc, current).
1298    return ValidateAndApplyPropertyDescriptor(op, extensible, desc, current, sCheckMode);
1299}
1300
1301bool JSObject::OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
1302                                         const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc,
1303                                         SCheckMode sCheckMode)
1304{
1305    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1306    // 1. Let current be O.[[GetOwnProperty]](P).
1307    JSHandle<JSTaggedValue> objValue(obj);
1308    ObjectOperator op(thread, objValue, key, OperatorType::OWN);
1309    return OrdinaryDefineOwnProperty(thread, &op, desc, sCheckMode);
1310}
1311
1312bool JSObject::OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1313                                         const PropertyDescriptor &desc, SCheckMode sCheckMode)
1314{
1315    JSHandle<JSTaggedValue> objValue(obj);
1316    ObjectOperator op(thread, objValue, index, OperatorType::OWN);
1317
1318    bool extensible = obj->IsExtensible();
1319    PropertyDescriptor current(thread);
1320    op.ToPropertyDescriptor(current);
1321    return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current, sCheckMode);
1322}
1323
1324bool JSObject::ValidateDataDescriptorWhenConfigurable(ObjectOperator *op, const PropertyDescriptor &desc,
1325                                                      const PropertyDescriptor &current, SCheckMode sCheckMode)
1326{
1327    // 8a i. Return false, if the [[Writable]] field of current is false and the [[Writable]] field of Desc
1328    // is true.
1329    if (!current.IsWritable() && desc.HasWritable() && desc.IsWritable()) {
1330        return false;
1331    }
1332    // 8a ii. If the [[Writable]] field of current is false, then
1333    if (!current.IsWritable()) {
1334        if (desc.HasValue() && !JSTaggedValue::SameValue(current.GetValue(), desc.GetValue())) {
1335            return false;
1336        }
1337    }
1338    if (op->HasHolder() && op->GetHolder()->IsJSShared() && (sCheckMode == SCheckMode::CHECK)) {
1339        if (!desc.HasValue()) {
1340            THROW_TYPE_ERROR_AND_RETURN(op->GetThread(), GET_MESSAGE_STRING(UpdateSendableAttributes), false);
1341        }
1342        if (!ClassHelper::MatchFieldType(current.GetSharedFieldType(), desc.GetValue().GetTaggedValue())) {
1343            THROW_TYPE_ERROR_AND_RETURN(op->GetThread(), GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), false);
1344        }
1345    }
1346    return true;
1347}
1348
1349// 9.1.6.3 ValidateAndApplyPropertyDescriptor (O, P, extensible, Desc, current)
1350bool JSObject::ValidateAndApplyPropertyDescriptor(ObjectOperator *op, bool extensible, const PropertyDescriptor &desc,
1351                                                  const PropertyDescriptor &current, SCheckMode sCheckMode)
1352{
1353    // 2. If current is undefined, then
1354    if (current.IsEmpty()) {
1355        // 2a. If extensible is false, return false.
1356        if (!(extensible || (op->HasHolder() && op->GetHolder()->IsJSShared() && sCheckMode == SCheckMode::SKIP))) {
1357            return false;
1358        }
1359        if (!op->HasHolder()) {
1360            return true;
1361        }
1362
1363        // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then
1364        PropertyAttributes attr(desc);
1365        bool success = false;
1366        if (!desc.IsAccessorDescriptor()) {
1367            op->UpdateDetector();
1368            success = op->AddPropertyInHolder(desc.GetValue(), attr);
1369        } else {  // is AccessorDescriptor
1370            // may GC in NewAccessorData, so we need to handle getter and setter.
1371            JSThread *thread = op->GetThread();
1372            JSHandle<AccessorData> accessor = thread->GetEcmaVM()->GetFactory()->NewAccessorData();
1373            if (desc.HasGetter()) {
1374                accessor->SetGetter(thread, desc.GetGetter());
1375            }
1376
1377            if (desc.HasSetter()) {
1378                accessor->SetSetter(thread, desc.GetSetter());
1379            }
1380            op->UpdateDetector();
1381            success = op->AddPropertyInHolder(JSHandle<JSTaggedValue>::Cast(accessor), attr);
1382        }
1383
1384        return success;
1385    }
1386
1387    // 3. Return true, if every field in Desc is absent
1388    // 4. Return true, if every field in Desc also occurs in current and the value of every field in Desc is the
1389    // same value as the corresponding field in current when compared using the SameValue algorithm.
1390    if ((!desc.HasEnumerable() || desc.IsEnumerable() == current.IsEnumerable()) &&
1391        (!desc.HasConfigurable() || desc.IsConfigurable() == current.IsConfigurable()) &&
1392        (!desc.HasValue() || JSTaggedValue::SameValue(current.GetValue(), desc.GetValue())) &&
1393        (!desc.HasWritable() || (current.IsWritable() == desc.IsWritable())) &&
1394        (!desc.HasGetter() ||
1395         (current.HasGetter() && JSTaggedValue::SameValue(current.GetGetter(), desc.GetGetter()))) &&
1396        (!desc.HasSetter() ||
1397         (current.HasSetter() && JSTaggedValue::SameValue(current.GetSetter(), desc.GetSetter())))) {
1398        return true;
1399    }
1400
1401    // 5. If the [[Configurable]] field of current is false, then
1402    if (!current.IsConfigurable()) {
1403        // 5a. Return false, if the [[Configurable]] field of Desc is true.
1404        if (desc.HasConfigurable() && desc.IsConfigurable()) {
1405            return false;
1406        }
1407        // b. Return false, if the [[Enumerable]] field of Desc is present and the [[Enumerable]] fields of current
1408        // and Desc are the Boolean negation of each other.
1409        if (desc.HasEnumerable() && (desc.IsEnumerable() != current.IsEnumerable())) {
1410            return false;
1411        }
1412    }
1413
1414    // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
1415    if (desc.IsGenericDescriptor()) {
1416        // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have different results, then
1417    } else if (current.IsDataDescriptor() != desc.IsDataDescriptor()) {
1418        // 7a. Return false, if the [[Configurable]] field of current is false.
1419        if (!current.IsConfigurable()) {
1420            return false;
1421        }
1422        // 7b. If IsDataDescriptor(current) is true, then
1423        if (current.IsDataDescriptor()) {
1424            // 7bi. If O is not undefined, convert the property named P of object O from a data property to an
1425            // accessor property. Preserve the existing values of the converted property’s [[Configurable]] and
1426            // [[Enumerable]] attributes and set the rest of the property’s attributes to their default values.
1427        } else {
1428            // 7ci.  If O is not undefined, convert the property named P of object O from an accessor property to a
1429            // data property. Preserve the existing values of the converted property’s [[Configurable]] and
1430            // [[Enumerable]] attributes and set the rest of the property’s attributes to their default values.
1431        }
1432        // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
1433    } else if (current.IsDataDescriptor() && desc.IsDataDescriptor()) {
1434        // 8a. If the [[Configurable]] field of current is false, then
1435        if (!current.IsConfigurable() && !ValidateDataDescriptorWhenConfigurable(op, desc, current, sCheckMode)) {
1436            return false;
1437        }
1438        // 8b. Else the [[Configurable]] field of current is true, so any change is acceptable.
1439    } else {  // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true,
1440        // 9a. If the [[Configurable]] field of current is false, then
1441        if (!current.IsConfigurable()) {
1442            // i. Return false, if the [[Set]] field of Desc is present and SameValue(Desc.[[Set]], current.[[Set]])
1443            // is false.
1444            if (desc.HasSetter() && !JSTaggedValue::SameValue(current.GetSetter(), desc.GetSetter())) {
1445                return false;
1446            }
1447            // ii. Return false, if the [[Get]] field of Desc is present and SameValue(Desc.[[Get]],
1448            // current.[[Get]]) is false.
1449            if (desc.HasGetter() && !JSTaggedValue::SameValue(current.GetGetter(), desc.GetGetter())) {
1450                return false;
1451            }
1452        }
1453    }
1454
1455    if (op->HasHolder()) {
1456        // 10. If O is not undefined, then
1457        // a. For each field of Desc that is present, set the corresponding attribute of the property named P of object
1458        // O to the value of the field.
1459        if (!desc.HasValue() && desc.HasWritable() && current.HasValue()) {
1460            // [[Value]] and [[Writable]] attributes are set to the value of the corresponding field in Desc
1461            // if Desc has that field or to the attribute's default value otherwise.
1462            PropertyDescriptor newDesc = desc;
1463            JSHandle<JSTaggedValue> valueHandle = current.GetValue();
1464            if (valueHandle->IsPropertyBox()) {
1465                JSTaggedValue value = PropertyBox::Cast(valueHandle->GetTaggedObject())->GetValue();
1466                valueHandle = JSHandle<JSTaggedValue>(op->GetThread(), value);
1467            }
1468            newDesc.SetValue(valueHandle);
1469            op->UpdateDetector();
1470            return op->WriteDataPropertyInHolder(newDesc);
1471        }
1472        op->UpdateDetector();
1473        return op->WriteDataPropertyInHolder(desc);
1474    }
1475    return true;
1476}
1477
1478// 9.1.6.2 IsCompatiblePropertyDescriptor (Extensible, Desc, Current)
1479bool JSObject::IsCompatiblePropertyDescriptor(bool extensible, const PropertyDescriptor &desc,
1480                                              const PropertyDescriptor &current)
1481{
1482    // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined, Extensible, Desc, Current).
1483    ObjectOperator op;
1484    return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current);
1485}
1486
1487JSTaggedValue JSObject::GetPrototype(const JSHandle<JSObject> &obj)
1488{
1489    JSHClass *hclass = obj->GetJSHClass();
1490    return hclass->GetPrototype();
1491}
1492
1493bool JSObject::SetPrototype(JSThread *thread, const JSHandle<JSObject> &obj,
1494                            const JSHandle<JSTaggedValue> &proto,
1495                            bool isChangeProto)
1496{
1497    ASSERT_PRINT(proto->IsECMAObject() || proto->IsNull(), "proto must be object or null");
1498    JSTaggedValue current = JSObject::GetPrototype(obj);
1499    if (current == proto.GetTaggedValue()) {
1500        return true;
1501    }
1502    if (!obj->IsExtensible()) {
1503        return false;
1504    }
1505    bool done = false;
1506    JSMutableHandle<JSTaggedValue> tempProtoHandle(thread, proto.GetTaggedValue());
1507    while (!done) {
1508        if (tempProtoHandle->IsNull() || !tempProtoHandle->IsECMAObject()) {
1509            done = true;
1510        } else if (JSTaggedValue::SameValue(tempProtoHandle.GetTaggedValue(), obj.GetTaggedValue())) {
1511            return false;
1512        } else {
1513            if (tempProtoHandle->IsJSProxy()) {
1514                break;
1515            }
1516            tempProtoHandle.Update(JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(tempProtoHandle)));
1517            RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1518        }
1519    }
1520    ElementsKind oldKind = obj->GetJSHClass()->GetElementsKind();
1521    // map transition
1522    JSHClass::SetPrototypeTransition(thread, obj, proto, isChangeProto);
1523    TryMigrateToGenericKindForJSObject(thread, obj, oldKind);
1524    return true;
1525}
1526
1527bool JSObject::HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key)
1528{
1529    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1530    JSHandle<JSTaggedValue> objValue(obj);
1531    ObjectOperator op(thread, objValue, key);
1532
1533    JSHandle<JSTaggedValue> holder = op.GetHolder();
1534    if (holder->IsJSProxy()) {
1535        return JSProxy::HasProperty(thread, JSHandle<JSProxy>::Cast(holder), key);
1536    }
1537
1538    return op.IsFound();
1539}
1540
1541bool JSObject::HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index)
1542{
1543    JSHandle<JSTaggedValue> objValue(obj);
1544    ObjectOperator op(thread, objValue, index);
1545
1546    JSHandle<JSTaggedValue> holder = op.GetHolder();
1547    if (holder->IsJSProxy()) {
1548        JSHandle<JSTaggedValue> key(thread, JSTaggedValue(index));
1549        return JSProxy::HasProperty(thread, JSHandle<JSProxy>::Cast(holder), key);
1550    }
1551
1552    return op.IsFound();
1553}
1554
1555bool JSObject::PreventExtensions(JSThread *thread, const JSHandle<JSObject> &obj)
1556{
1557    if (obj->IsExtensible()) {
1558        JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
1559        JSHandle<JSHClass> newHclass = JSHClass::TransitionExtension(thread, jshclass);
1560#if ECMASCRIPT_ENABLE_IC
1561        JSHClass::NotifyHclassChanged(thread, jshclass, newHclass);
1562#endif
1563        ElementsKind oldKind = obj->GetJSHClass()->GetElementsKind();
1564        JSHClass::RestoreElementsKindToGeneric(*newHclass);
1565        obj->SynchronizedSetClass(thread, *newHclass);
1566        TryMigrateToGenericKindForJSObject(thread, obj, oldKind);
1567    }
1568
1569    return true;
1570}
1571
1572// 9.1.12 [[OwnPropertyKeys]] ( )
1573JSHandle<TaggedArray> JSObject::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj)
1574{
1575    uint32_t numOfElements = obj->GetNumberOfElements();
1576    uint32_t keyLen = numOfElements + obj->GetNumberOfKeys();
1577
1578    JSHandle<TaggedArray> keyArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(keyLen);
1579
1580    if (numOfElements > 0) {
1581        GetAllElementKeys(thread, obj, 0, keyArray);
1582    }
1583    GetAllKeys(thread, obj, static_cast<int32_t>(numOfElements), keyArray);
1584    return keyArray;
1585}
1586
1587JSHandle<TaggedArray> JSObject::GetAllPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t filter)
1588{
1589    JSMutableHandle<JSObject> currentObj(thread, obj);
1590    JSMutableHandle<JSTaggedValue> currentObjValue(thread, currentObj);
1591
1592    uint32_t curObjNumberOfElements = currentObj->GetNumberOfElements();
1593    uint32_t curObjNumberOfKeys = currentObj->GetNumberOfKeys();
1594    uint32_t curObjectKeysLength = curObjNumberOfElements + curObjNumberOfKeys;
1595    uint32_t retArrayLength = curObjectKeysLength;
1596    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1597    JSMutableHandle<TaggedArray> retArray(thread, factory->NewTaggedArray(retArrayLength));
1598    uint32_t retArrayEffectivelength = 0;
1599
1600    do {
1601        curObjNumberOfElements = currentObj->GetNumberOfElements();
1602        curObjNumberOfKeys = currentObj->GetNumberOfKeys();
1603        curObjectKeysLength = curObjNumberOfElements + curObjNumberOfKeys;
1604        uint32_t minRequireLength = curObjectKeysLength + retArrayEffectivelength;
1605        if (retArrayLength < minRequireLength) {
1606            // expand retArray
1607            if (retArrayLength != 0) {
1608                retArray.Update(factory->NewAndCopyTaggedArray(retArray, minRequireLength, retArrayLength));
1609            } else {
1610                retArray.Update(factory->NewTaggedArray(minRequireLength));
1611            }
1612            retArrayLength = minRequireLength;
1613        }
1614
1615        GetAllElementKeysByFilter(thread, currentObj, retArray, retArrayEffectivelength, filter);
1616
1617        GetAllKeysByFilter(thread, currentObj, retArrayEffectivelength, retArray, filter);
1618        bool isInculdePrototypes = (filter & NATIVE_KEY_INCLUDE_PROTOTYPES);
1619        if (!isInculdePrototypes) {
1620            break;
1621        }
1622        currentObj.Update(GetPrototype(currentObj));
1623        currentObjValue.Update(currentObj);
1624    } while (currentObjValue->IsHeapObject());
1625
1626    if (retArrayEffectivelength == 0 && (filter & NATIVE_KEY_OWN_ONLY)) {
1627        return retArray;
1628    }
1629    JSMutableHandle<JSTaggedValue> element(thread, JSTaggedValue::Undefined());
1630    if (filter & NATIVE_KEY_NUMBERS_TO_STRINGS) {
1631        for (uint32_t i = 0; i < retArrayEffectivelength; i++) {
1632            element.Update(retArray->Get(i));
1633            if (element->IsNumber()) {
1634                retArray->Set(thread, i, base::NumberHelper::NumberToString(thread,
1635                    JSTaggedValue(element->GetNumber())));
1636            }
1637        }
1638    }
1639    uint32_t elementIndex = 0;
1640    if (filter & NATIVE_KEY_SKIP_STRINGS) {
1641        while ((retArrayEffectivelength > 0) && (elementIndex < retArrayEffectivelength)) {
1642            if (retArray->Get(elementIndex).IsString()) {
1643                TaggedArray::RemoveElementByIndex(thread, retArray, elementIndex, retArrayEffectivelength);
1644                retArrayEffectivelength--;
1645            } else {
1646                elementIndex++;
1647            }
1648        }
1649    }
1650    if (retArray->GetLength() > retArrayEffectivelength) {
1651        retArray->Trim(thread, retArrayEffectivelength);
1652    }
1653    return retArray;
1654}
1655
1656void JSObject::CollectEnumKeysAlongProtoChain(JSThread *thread, const JSHandle<JSObject> &obj,
1657                                              JSHandle<TaggedArray> keyArray, uint32_t *keys,
1658                                              JSHandle<TaggedQueue> shadowQueue, int32_t lastLength)
1659{
1660    ASSERT(!obj->IsJSGlobalObject());
1661
1662    TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
1663    if (!array->IsDictionaryMode()) {
1664        JSHClass *jsHclass = obj->GetJSHClass();
1665        int end = static_cast<int>(jsHclass->NumberOfProps());
1666        if (end > 0) {
1667            LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject())
1668                ->GetAllEnumKeys(thread, end, *keys, keyArray, keys, shadowQueue, obj, lastLength);
1669        }
1670        return;
1671    }
1672    NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
1673    dict->GetAllEnumKeys(thread, *keys, keyArray, keys, shadowQueue, lastLength);
1674}
1675
1676void JSObject::AppendOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj,
1677                                         JSHandle<TaggedArray> keyArray, uint32_t *keys,
1678                                         JSHandle<TaggedQueue> shadowQueue)
1679{
1680    int32_t lastLength = *keys;
1681    uint32_t numOfElements = obj->GetNumberOfElements();
1682    if (numOfElements > 0) {
1683        CollectEnumElementsAlongProtoChain(thread, obj, *keys, keyArray, keys, lastLength);
1684    }
1685    CollectEnumKeysAlongProtoChain(thread, obj, keyArray, keys, shadowQueue, lastLength);
1686}
1687
1688JSHandle<TaggedArray> JSObject::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj)
1689{
1690    uint32_t numOfElements = obj->GetNumberOfElements();
1691    uint32_t keyLen = numOfElements + obj->GetNumberOfKeys();
1692
1693    JSHandle<TaggedArray> keyArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(keyLen);
1694
1695    if (numOfElements > 0) {
1696        GetEnumElementKeys(thread, obj, 0, keyArray);
1697    }
1698    GetAllEnumKeys(thread, obj, static_cast<int32_t>(numOfElements), keyArray);
1699    return keyArray;
1700}
1701
1702JSHandle<JSObject> JSObject::ObjectCreate(JSThread *thread, const JSHandle<JSObject> &proto)
1703{
1704    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1705    JSHandle<JSFunction> constructor(env->GetObjectFunction());
1706    JSHandle<JSObject> objHandle = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(constructor);
1707    SetPrototype(thread, objHandle, JSHandle<JSTaggedValue>(proto));
1708    return objHandle;
1709}
1710
1711// 7.3.4 CreateDataProperty (O, P, V)
1712bool JSObject::CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1713                                  const JSHandle<JSTaggedValue> &value, SCheckMode sCheckMode)
1714{
1715    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1716    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1717    if (!JSHandle<JSTaggedValue>::Cast(obj)->IsJSShared()) {
1718        sCheckMode = SCheckMode::CHECK;
1719    }
1720    auto result = ObjectFastOperator::SetPropertyByValue<ObjectFastOperator::Status::DefineSemantics>(
1721        thread, obj.GetTaggedValue(), key.GetTaggedValue(), value.GetTaggedValue(), sCheckMode);
1722    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1723    if (!result.IsHole()) {
1724        return !result.IsException();
1725    }
1726    PropertyDescriptor desc(thread, value, true, true, true);
1727    return JSTaggedValue::DefineOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key, desc, sCheckMode);
1728}
1729
1730bool JSObject::CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1731                                  const JSHandle<JSTaggedValue> &value, SCheckMode sCheckMode)
1732{
1733    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1734    auto result = ObjectFastOperator::SetPropertyByIndex<ObjectFastOperator::Status::DefineSemantics>
1735            (thread, obj.GetTaggedValue(), index, value.GetTaggedValue());
1736    if (!result.IsHole()) {
1737        return !result.IsException();
1738    }
1739    PropertyDescriptor desc(thread, value, true, true, true);
1740    return DefineOwnProperty(thread, obj, index, desc, sCheckMode);
1741}
1742
1743// 7.3.5 CreateMethodProperty (O, P, V)
1744bool JSObject::CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj,
1745                                         const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
1746                                         SCheckMode sCheckMode)
1747{
1748    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1749    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1750
1751    bool success = CreateDataProperty(thread, obj, key, value, sCheckMode);
1752    if (!success) {
1753        THROW_TYPE_ERROR_AND_RETURN(thread, "failed to create data property", success);
1754    }
1755    return success;
1756}
1757
1758bool JSObject::CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1759                                         const JSHandle<JSTaggedValue> &value,  SCheckMode sCheckMode)
1760{
1761    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1762
1763    bool success = CreateDataProperty(thread, obj, index, value, sCheckMode);
1764    if (!success) {
1765        THROW_TYPE_ERROR_AND_RETURN(thread, "failed to create data property", success);
1766    }
1767    return success;
1768}
1769// 7.3.6 CreateDataPropertyOrThrow (O, P, V)
1770bool JSObject::CreateMethodProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1771                                    const JSHandle<JSTaggedValue> &value)
1772{
1773    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1774    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1775
1776    PropertyDescriptor desc(thread, value, true, false, true);
1777    return DefineOwnProperty(thread, obj, key, desc);
1778}
1779
1780JSHandle<JSTaggedValue> JSObject::CallFunction(JSThread *thread, const JSHandle<JSTaggedValue> &func)
1781{
1782    if (func->IsUndefined() || func->IsNull()) {
1783        return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
1784    }
1785    if (!func->IsCallable()) {
1786        THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not Callable", func);
1787    }
1788    return func;
1789}
1790
1791// 7.3.9 GetMethod (O, P)
1792JSHandle<JSTaggedValue> JSObject::GetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1793                                            const JSHandle<JSTaggedValue> &key)
1794{
1795    JSHandle<JSTaggedValue> func = JSTaggedValue::GetProperty(thread, obj, key).GetValue();
1796    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1797    func = CallFunction(thread, func);
1798    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1799    return func;
1800}
1801
1802JSHandle<JSTaggedValue> JSObject::FastGetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1803                                                const JSHandle<JSTaggedValue> &key)
1804{
1805    JSHandle<JSTaggedValue> func(thread, ObjectFastOperator::FastGetPropertyByName(thread, obj.GetTaggedValue(),
1806                                                                                   key.GetTaggedValue()));
1807    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1808    func = CallFunction(thread, func);
1809    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1810    return func;
1811}
1812
1813// 7.3.14 SetIntegrityLevel (O, level)
1814bool JSObject::SetIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level)
1815{
1816    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1817    ASSERT_PRINT((level == IntegrityLevel::SEALED || level == IntegrityLevel::FROZEN),
1818                 "level is not a valid IntegrityLevel");
1819
1820    bool status = JSTaggedValue::PreventExtensions(thread, JSHandle<JSTaggedValue>(obj));
1821    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1822    if (!status) {
1823        return false;
1824    }
1825
1826    JSHandle<TaggedArray> jshandleKeys =
1827        JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>(obj));
1828    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1829    PropertyDescriptor descNoConf(thread);
1830    descNoConf.SetConfigurable(false);
1831    PropertyDescriptor descNoConfWrite(thread);
1832    descNoConfWrite.SetWritable(false);
1833    descNoConfWrite.SetConfigurable(false);
1834
1835    if (level == IntegrityLevel::SEALED) {
1836        uint32_t length = jshandleKeys->GetLength();
1837        if (length == 0) {
1838            return true;
1839        }
1840        auto key = jshandleKeys->Get(0);
1841        JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1842        for (uint32_t i = 0; i < length; i++) {
1843            auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1844            handleKey.Update(taggedKey);
1845            [[maybe_unused]] bool success =
1846                JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(obj), handleKey, descNoConf);
1847            RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1848        }
1849    } else {
1850        uint32_t length = jshandleKeys->GetLength();
1851        if (length == 0) {
1852            return true;
1853        }
1854        auto key = jshandleKeys->Get(0);
1855        JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1856        for (uint32_t i = 0; i < length; i++) {
1857            auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1858            handleKey.Update(taggedKey);
1859            PropertyDescriptor currentDesc(thread);
1860            bool curDescStatus =
1861                JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), handleKey, currentDesc);
1862            RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1863            if (curDescStatus) {
1864                PropertyDescriptor desc = currentDesc.IsAccessorDescriptor() ? descNoConf : descNoConfWrite;
1865                [[maybe_unused]] bool success =
1866                    JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(obj), handleKey, desc);
1867                RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1868            }
1869        }
1870    }
1871    return true;
1872}
1873
1874bool JSObject::FreezeSharedObject(JSThread *thread, const JSHandle<JSObject> &obj)
1875{
1876    ASSERT_PRINT(JSHandle<JSTaggedValue>(obj)->IsJSSharedObject() ||
1877                 JSHandle<JSTaggedValue>(obj)->IsJSSharedFunction() ||
1878                 JSHandle<JSTaggedValue>(obj)->IsJSSharedAsyncFunction(),
1879                 "Obj is not a valid shared object");
1880    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1881    // It is not extensible for shared object.
1882    if (obj->IsExtensible()) {
1883        return false;
1884    }
1885    JSHandle<JSHClass> hclass(thread, obj->GetClass());
1886    auto newClass = JSHClass::Clone(thread, hclass);
1887    if (!hclass->IsDictionaryMode()) {
1888        uint32_t propNumber = hclass->NumberOfProps();
1889        JSHandle<LayoutInfo> layoutInfo(thread, hclass->GetLayout());
1890        JSHandle<LayoutInfo> newLayoutInfo = factory->CreateSLayoutInfo(propNumber);
1891        for (uint32_t i = 0; i < propNumber; i++) {
1892            JSTaggedValue key = layoutInfo->GetKey(i);
1893            PropertyAttributes attr = layoutInfo->GetAttr(i);
1894            attr.SetWritable(false);
1895            newLayoutInfo->AddKey(thread, i, key, attr);
1896        }
1897        newClass->SetLayout(thread, newLayoutInfo);
1898        obj->SynchronizedSetClass(thread, *newClass);
1899    } else {
1900        auto dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
1901        dict->UpdateAllAttributesToNoWitable(thread);
1902    }
1903    return true;
1904}
1905
1906// 7.3.15 TestIntegrityLevel (O, level)
1907bool JSObject::TestIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level)
1908{
1909    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1910    ASSERT_PRINT((level == IntegrityLevel::SEALED || level == IntegrityLevel::FROZEN),
1911                 "level is not a valid IntegrityLevel");
1912
1913    bool status = JSHandle<JSTaggedValue>(obj)->IsExtensible(thread);
1914    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1915    if (status) {
1916        return false;
1917    }
1918
1919    JSHandle<TaggedArray> jshandleKeys =
1920        JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>(obj));
1921    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1922    uint32_t length = jshandleKeys->GetLength();
1923    if (length == 0) {
1924        return true;
1925    }
1926    auto key = jshandleKeys->Get(0);
1927    JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1928    for (uint32_t i = 0; i < length; i++) {
1929        auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1930        handleKey.Update(taggedKey);
1931        PropertyDescriptor currentDesc(thread);
1932        bool curDescStatus =
1933            JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), handleKey, currentDesc);
1934        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1935        if (curDescStatus) {
1936            if (currentDesc.IsConfigurable()) {
1937                return false;
1938            }
1939            if (level == IntegrityLevel::FROZEN &&
1940                currentDesc.IsDataDescriptor() && currentDesc.IsWritable()) {
1941                return false;
1942            }
1943        }
1944    }
1945    return true;
1946}
1947
1948// 7.3.21 EnumerableOwnNames (O)
1949JSHandle<TaggedArray> JSObject::EnumerableOwnNames(JSThread *thread, const JSHandle<JSObject> &obj)
1950{
1951    ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
1952    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1953    JSHandle<JSTaggedValue> tagObj(obj);
1954    // fast mode
1955    if (tagObj->IsJSObject() && !tagObj->IsTypedArray() && !tagObj->IsModuleNamespace()) {
1956        uint32_t copyLengthOfKeys = 0;
1957        uint32_t copyLengthOfElements = 0;
1958        auto keyElementPair = GetOwnEnumerableNamesInFastMode(thread, obj, &copyLengthOfKeys, &copyLengthOfElements);
1959        JSHandle<TaggedArray> keyArray = keyElementPair.first;
1960        JSHandle<TaggedArray> elementArray = keyElementPair.second;
1961        JSHandle<TaggedArray> keys;
1962        if (copyLengthOfKeys != 0 && copyLengthOfElements != 0) {
1963            keys = TaggedArray::AppendSkipHole(thread, elementArray, keyArray, copyLengthOfKeys + copyLengthOfElements);
1964        } else if (copyLengthOfKeys != 0) {
1965            if (copyLengthOfKeys < keyArray->GetLength()) {
1966                // keyArray will skip nonEnumerable properties, need re-set length.
1967                keyArray->Trim(thread, copyLengthOfKeys);
1968            }
1969            return keyArray;
1970        } else if (copyLengthOfElements != 0) {
1971            if (copyLengthOfElements < elementArray->GetLength()) {
1972                // elementArray will skip hole value, need re-set length.
1973                elementArray->Trim(thread, copyLengthOfElements);
1974            }
1975            return elementArray;
1976        } else {
1977            keys = factory->EmptyArray();
1978        }
1979        return keys;
1980    }
1981
1982    uint32_t copyLength = 0;
1983    JSHandle<TaggedArray> keys = JSTaggedValue::GetOwnPropertyKeys(thread, tagObj);
1984    RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1985    uint32_t length = keys->GetLength();
1986
1987    JSHandle<TaggedArray> names = factory->NewTaggedArray(length);
1988    JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
1989    for (uint32_t i = 0; i < length; i++) {
1990        keyHandle.Update(keys->Get(i));
1991        if (keyHandle->IsString()) {
1992            PropertyDescriptor desc(thread);
1993            bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj),
1994                                                        keyHandle, desc);
1995            RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1996
1997            if (status && desc.IsEnumerable()) {
1998                names->Set(thread, copyLength, keyHandle);
1999                copyLength++;
2000            }
2001        }
2002    }
2003
2004    return factory->CopyArray(names, length, copyLength);
2005}
2006
2007void JSObject::EnumerableOwnPropertyNamesHelper(JSThread *thread, const JSHandle<JSObject> &obj,
2008    const JSHandle<TaggedArray> &arr, JSHandle<TaggedArray> &prop, uint32_t &index, bool &fastMode, PropertyKind kind)
2009{
2010    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2011    JSHandle<JSHClass> objClass(thread, obj->GetJSHClass());
2012    uint32_t length = arr->GetLength();
2013    for (uint32_t i = 0; i < length; i++) {
2014        key.Update(arr->Get(thread, i));
2015        if (!JSTaggedValue::IsPropertyKey(key)) {
2016            break;
2017        }
2018        JSTaggedValue value = JSTaggedValue::Hole();
2019        if (fastMode) {
2020            value = ObjectFastOperator::GetPropertyByValue<ObjectFastOperator::Status::UseOwn>
2021                    (thread, obj.GetTaggedValue(), key.GetTaggedValue());
2022            RETURN_IF_ABRUPT_COMPLETION(thread);
2023        }
2024        if (value.IsHole()) {
2025            PropertyDescriptor desc(thread);
2026            bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), key, desc);
2027            RETURN_IF_ABRUPT_COMPLETION(thread);
2028            if (!status || !desc.IsEnumerable()) {
2029                continue;
2030            }
2031            if (desc.HasValue()) {
2032                value = desc.GetValue().GetTaggedValue();
2033            } else {
2034                OperationResult opResult = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key);
2035                RETURN_IF_ABRUPT_COMPLETION(thread);
2036                value = opResult.GetValue().GetTaggedValue();
2037            }
2038        }
2039        index = SetValuesOrEntries(thread, prop, index, key, JSHandle<JSTaggedValue>(thread, value), kind);
2040        fastMode = fastMode ? CheckHClassHit(obj, objClass) : fastMode;
2041    }
2042}
2043
2044JSHandle<TaggedArray> JSObject::EnumerableOwnPropertyNames(JSThread *thread, const JSHandle<JSObject> &obj,
2045                                                           PropertyKind kind)
2046{
2047    // 1. Assert: Type(O) is Object.
2048    ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
2049
2050    // 2. Let ownKeys be ? O.[[OwnPropertyKeys]]().
2051    JSHandle<JSTaggedValue> tagObj(obj);
2052    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2053    if (tagObj->IsJSObject() && !tagObj->IsJSProxy() && !tagObj->IsTypedArray() && !tagObj->IsModuleNamespace()) {
2054        uint32_t copyLengthOfKeys = 0;
2055        uint32_t copyLengthOfElements = 0;
2056        uint32_t index = 0;
2057        bool fastMode = true;
2058        auto keyElementPair = GetOwnEnumerableNamesInFastMode(thread, obj, &copyLengthOfKeys, &copyLengthOfElements);
2059        JSHandle<TaggedArray> keyArray = keyElementPair.first;
2060        JSHandle<TaggedArray> elementArray = keyElementPair.second;
2061        JSHandle<TaggedArray> properties = factory->NewTaggedArray(copyLengthOfKeys + copyLengthOfElements);
2062        if (copyLengthOfElements != 0) {
2063            EnumerableOwnPropertyNamesHelper(thread, obj, elementArray, properties, index, fastMode, kind);
2064        }
2065        if (copyLengthOfKeys != 0) {
2066            EnumerableOwnPropertyNamesHelper(thread, obj, keyArray, properties, index, fastMode, kind);
2067        }
2068        if (UNLIKELY(!fastMode && index < copyLengthOfKeys + copyLengthOfElements)) {
2069            properties->Trim(thread, index);
2070        }
2071        return properties;
2072    }
2073
2074    JSHandle<TaggedArray> ownKeys = JSTaggedValue::GetOwnPropertyKeys(thread, tagObj);
2075    RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
2076
2077    // 3. Let properties be a new empty List.
2078    uint32_t length = ownKeys->GetLength();
2079    JSHandle<TaggedArray> properties = factory->NewTaggedArray(length);
2080
2081    // 4. For each element key of ownKeys, do
2082    // a. If Type(key) is String, then
2083    //     i. Let desc be ? O.[[GetOwnProperty]](key).
2084    //     ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2085    //         1. If kind is key, append key to properties.
2086    //         2. Else,
2087    //            a. Let value be ? Get(O, key).
2088    //            b. If kind is value, append value to properties.
2089    //            c. Else,
2090    //               i. Assert: kind is key+value.
2091    //               ii. Let entry be ! CreateArrayFromList(« key, value »).
2092    //               iii. Append entry to properties.
2093    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2094    uint32_t index = 0;
2095    for (uint32_t i = 0; i < length; i++) {
2096        key.Update(ownKeys->Get(thread, i));
2097        if (key->IsString()) {
2098            PropertyDescriptor desc(thread);
2099            bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj),
2100                                                        key, desc);
2101            RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
2102            if (status && desc.IsEnumerable()) {
2103                if (kind == PropertyKind::KEY) {
2104                    properties->Set(thread, index++, key);
2105                } else {
2106                    OperationResult result =
2107                        JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key);
2108                    RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
2109                    JSHandle<JSTaggedValue> value = result.GetValue();
2110                    index = SetValuesOrEntries(thread, properties, index, key, value, kind);
2111                }
2112            }
2113        }
2114    }
2115
2116    if (UNLIKELY(index < length)) {
2117        properties->Trim(thread, index);
2118    }
2119    // 5. Return properties.
2120    return properties;
2121}
2122
2123JSHandle<GlobalEnv> JSObject::GetFunctionRealm(JSThread *thread, const JSHandle<JSTaggedValue> &object)
2124{
2125    // 1. Assert: obj is a callable object.
2126    ASSERT(object->IsCallable());
2127    // 2. If obj has a [[Realm]] internal slot, then return obj’s [[Realm]] internal slot.
2128    // 3. If obj is a Bound Function exotic object, then
2129    if (object->IsBoundFunction()) {
2130        // a. Let target be obj’s [[BoundTargetFunction]] internal slot.
2131        JSHandle<JSTaggedValue> target(thread, JSHandle<JSBoundFunction>(object)->GetBoundTarget());
2132        // b. Return GetFunctionRealm(target).
2133        return GetFunctionRealm(thread, target);
2134    }
2135    // 4. If obj is a Proxy exotic object, then
2136    if (object->IsJSProxy()) {
2137        // a. If the value of the [[ProxyHandler]] internal slot of obj is null, throw a TypeError exception.
2138        if (JSHandle<JSProxy>(object)->GetHandler().IsNull()) {
2139            THROW_TYPE_ERROR_AND_RETURN(thread, "JSObject::GetFunctionRealm: handler is null",
2140                                        JSHandle<GlobalEnv>(thread, JSTaggedValue::Exception()));
2141        }
2142        // b. Let proxyTarget be the value of obj’s [[ProxyTarget]] internal slot.
2143        JSHandle<JSTaggedValue> proxyTarget(thread, JSHandle<JSProxy>(object)->GetTarget());
2144        return GetFunctionRealm(thread, proxyTarget);
2145    }
2146
2147    if (object->IsJSShared()) {
2148        // LexicalEnv in sharedConstructor is constructor itself. And Shared Constructors shares the same GlobalEnv.
2149        return thread->GetEcmaVM()->GetGlobalEnv();
2150    }
2151
2152    JSTaggedValue maybeGlobalEnv = JSHandle<JSFunction>(object)->GetLexicalEnv();
2153    while (!maybeGlobalEnv.IsJSGlobalEnv()) {
2154        if (maybeGlobalEnv.IsUndefined()) {
2155            return thread->GetEcmaVM()->GetGlobalEnv();
2156        }
2157        maybeGlobalEnv = LexicalEnv::Cast(maybeGlobalEnv.GetTaggedObject())->GetParentEnv();
2158    }
2159    return JSHandle<GlobalEnv>(thread, maybeGlobalEnv);
2160}
2161
2162bool JSObject::InstanceOf(JSThread *thread, const JSHandle<JSTaggedValue> &object,
2163                          const JSHandle<JSTaggedValue> &target)
2164{
2165    // 1. If Type(target) is not Object, throw a TypeError exception.
2166    if (!target->IsECMAObject()) {
2167        THROW_TYPE_ERROR_AND_RETURN(thread, "InstanceOf error when type of target is not Object", false);
2168    }
2169
2170    EcmaVM *vm = thread->GetEcmaVM();
2171    // 2. Let instOfHandler be GetMethod(target, @@hasInstance).
2172    JSHandle<JSTaggedValue> instOfHandler = FastGetMethod(thread, target, vm->GetGlobalEnv()->GetHasInstanceSymbol());
2173
2174    // 3. ReturnIfAbrupt(instOfHandler).
2175    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
2176
2177    // 4. If instOfHandler is not undefined, then
2178    if (!instOfHandler->IsUndefined()) {
2179        // a. Return ! ToBoolean(? Call(instOfHandler, target, «object»)).
2180        JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2181        EcmaRuntimeCallInfo *info =
2182            EcmaInterpreter::NewRuntimeCallInfo(thread, instOfHandler, target, undefined, 1);
2183        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
2184        info->SetCallArg(object.GetTaggedValue());
2185        JSTaggedValue tagged = JSFunction::Call(info);
2186        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
2187        return tagged.ToBoolean();
2188    }
2189
2190    // 5. If IsCallable(target) is false, throw a TypeError exception.
2191    if (!target->IsCallable()) {
2192        THROW_TYPE_ERROR_AND_RETURN(thread, "InstanceOf error when target is not Callable", false);
2193    }
2194
2195    // 6. Return ? OrdinaryHasInstance(target, object).
2196    return JSFunction::OrdinaryHasInstance(thread, target, object);
2197}
2198
2199// ecma6.0 6.2.4.4
2200JSHandle<JSTaggedValue> JSObject::FromPropertyDescriptor(JSThread *thread, const PropertyDescriptor &desc)
2201{
2202    // 1. If Desc is undefined, return undefined
2203    if (desc.IsEmpty()) {
2204        return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
2205    }
2206
2207    // 2. Let obj be ObjectCreate(%ObjectPrototype%).
2208    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
2209    JSHandle<JSFunction> objFunc(env->GetObjectFunction());
2210    JSHandle<JSObject> objHandle = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(objFunc);
2211
2212    auto globalConst = thread->GlobalConstants();
2213    // 4. If Desc has a [[Value]] field, then Perform CreateDataProperty(obj, "value", Desc.[[Value]]).
2214    if (desc.HasValue()) {
2215        JSHandle<JSTaggedValue> valueStr = globalConst->GetHandledValueString();
2216        bool success = CreateDataProperty(thread, objHandle, valueStr, desc.GetValue());
2217        RASSERT_PRINT(success, "CreateDataProperty must be success");
2218    }
2219    // 5. If Desc has a [[Writable]] field, then Perform CreateDataProperty(obj, "writable", Desc.[[Writable]]).
2220    if (desc.HasWritable()) {
2221        JSHandle<JSTaggedValue> writableStr = globalConst->GetHandledWritableString();
2222        JSHandle<JSTaggedValue> writable(thread, JSTaggedValue(desc.IsWritable()));
2223        [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, writableStr, writable);
2224        ASSERT_PRINT(success, "CreateDataProperty must be success");
2225    }
2226    // 6. If Desc has a [[Get]] field, then Perform CreateDataProperty(obj, "get", Desc.[[Get]]).
2227    if (desc.HasGetter()) {
2228        JSHandle<JSTaggedValue> getStr = globalConst->GetHandledGetString();
2229        bool success = CreateDataProperty(thread, objHandle, getStr, desc.GetGetter());
2230        RASSERT_PRINT(success, "CreateDataProperty must be success");
2231    }
2232    // 7. If Desc has a [[Set]] field, then Perform CreateDataProperty(obj, "set", Desc.[[Set]])
2233    if (desc.HasSetter()) {
2234        JSHandle<JSTaggedValue> setStr = globalConst->GetHandledSetString();
2235        bool success = CreateDataProperty(thread, objHandle, setStr, desc.GetSetter());
2236        RASSERT_PRINT(success, "CreateDataProperty must be success");
2237    }
2238    // 8. If Desc has an [[Enumerable]] field, then Perform CreateDataProperty(obj, "enumerable",
2239    // Desc.[[Enumerable]]).
2240    if (desc.HasEnumerable()) {
2241        JSHandle<JSTaggedValue> enumerableStr = globalConst->GetHandledEnumerableString();
2242        JSHandle<JSTaggedValue> enumerable(thread, JSTaggedValue(desc.IsEnumerable()));
2243        [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, enumerableStr, enumerable);
2244        ASSERT_PRINT(success, "CreateDataProperty must be success");
2245    }
2246    // 9. If Desc has a [[Configurable]] field, then Perform CreateDataProperty(obj , "configurable",
2247    // Desc.[[Configurable]]).
2248    if (desc.HasConfigurable()) {
2249        JSHandle<JSTaggedValue> configurableStr = globalConst->GetHandledConfigurableString();
2250        JSHandle<JSTaggedValue> configurable(thread, JSTaggedValue(desc.IsConfigurable()));
2251        [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, configurableStr, configurable);
2252        ASSERT_PRINT(success, "CreateDataProperty must be success");
2253    }
2254    return JSHandle<JSTaggedValue>(objHandle);
2255}
2256
2257bool JSObject::ToPropertyDescriptorFast(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc)
2258{
2259    auto *hclass = obj->GetTaggedObject()->GetClass();
2260    JSType jsType = hclass->GetObjectType();
2261    if (jsType != JSType::JS_OBJECT) {
2262        return false;
2263    }
2264    if (hclass->IsDictionaryMode()) {
2265        return false;
2266    }
2267    auto env = thread->GetEcmaVM()->GetGlobalEnv();
2268    auto globalConst = thread->GlobalConstants();
2269    if (hclass->GetPrototype() != env->GetObjectFunctionPrototype().GetTaggedValue()) {
2270        return false;
2271    }
2272    if (JSObject::Cast(hclass->GetPrototype().GetTaggedObject())->GetClass() !=
2273        env->GetObjectFunctionPrototypeClass().GetObject<JSHClass>()) {
2274        return false;
2275    }
2276    LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
2277    uint32_t propsNumber = hclass->NumberOfProps();
2278    for (uint32_t i = 0; i < propsNumber; i++) {
2279        auto attr = layoutInfo->GetAttr(i);
2280        if (attr.IsAccessor()) {
2281            return false;
2282        }
2283        auto key = layoutInfo->GetKey(i);
2284        auto value = JSObject::Cast(obj->GetTaggedObject())->GetProperty(hclass, attr);
2285        if (key == globalConst->GetEnumerableString()) {
2286            bool enumerable = value.ToBoolean();
2287            desc.SetEnumerable(enumerable);
2288        } else if (key == globalConst->GetConfigurableString()) {
2289            bool configurable = value.ToBoolean();
2290            desc.SetConfigurable(configurable);
2291        } else if (key == globalConst->GetValueString()) {
2292            auto handleValue = JSHandle<JSTaggedValue>(thread, value);
2293            desc.SetValue(handleValue);
2294        } else if (key == globalConst->GetWritableString()) {
2295            bool writable = value.ToBoolean();
2296            desc.SetWritable(writable);
2297        } else if (key == globalConst->GetGetString()) {
2298            if (!value.IsCallable()) {
2299                return false;
2300            }
2301            auto getter = JSHandle<JSTaggedValue>(thread, value);
2302            desc.SetGetter(getter);
2303        } else if (key == globalConst->GetSetString()) {
2304            if (!value.IsCallable()) {
2305                return false;
2306            }
2307            auto setter = JSHandle<JSTaggedValue>(thread, value);
2308            desc.SetSetter(setter);
2309        }
2310    }
2311
2312    if (desc.IsAccessorDescriptor()) {
2313        // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, throw a TypeError exception.
2314        if (desc.HasValue() || desc.HasWritable()) {
2315            THROW_TYPE_ERROR_AND_RETURN(thread, "either Value or Writable is present", true);
2316        }
2317    }
2318    return true;
2319}
2320
2321// ecma6.0 6.2.4.5 ToPropertyDescriptor ( Obj )
2322void JSObject::ToPropertyDescriptor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc)
2323{
2324    if (!obj->IsECMAObject()) {
2325        // 2. If Type(Obj) is not Object, throw a TypeError exception.
2326        THROW_TYPE_ERROR(thread, "ToPropertyDescriptor error obj is not Object");
2327    }
2328
2329    if (ToPropertyDescriptorFast(thread, obj, desc)) {
2330        return;
2331    }
2332    auto globalConst = thread->GlobalConstants();
2333    // 3. Let desc be a new Property Descriptor that initially has no fields.
2334    // 4. Let hasEnumerable be HasProperty(Obj, "enumerable")
2335    {
2336        ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetEnumerableString());
2337        if (op.IsFound()) {
2338            auto value = op.FastGetValue();
2339            bool enumerable = value->IsException() ? false : value->ToBoolean();
2340            desc.SetEnumerable(enumerable);
2341        }
2342    }
2343    // 7. Let hasConfigurable be HasProperty(Obj, "configurable").
2344    {
2345        ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetConfigurableString());
2346        if (op.IsFound()) {
2347            auto value = op.FastGetValue();
2348            bool conf = value->IsException() ? false : value->ToBoolean();
2349            desc.SetConfigurable(conf);
2350        }
2351    }
2352    // 10. Let hasValue be HasProperty(Obj, "value").
2353    {
2354        ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetValueString());
2355        if (op.IsFound()) {
2356            JSHandle<JSTaggedValue> prop = op.FastGetValue();
2357            desc.SetValue(prop);
2358        }
2359    }
2360    // 13. Let hasWritable be HasProperty(Obj, "writable").
2361    {
2362        ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetWritableString());
2363        if (op.IsFound()) {
2364            auto value = op.FastGetValue();
2365            bool writable = value->IsException() ? false : value->ToBoolean();
2366            desc.SetWritable(writable);
2367        }
2368    }
2369    // 16. Let hasGet be HasProperty(Obj, "get").
2370    {
2371        ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetGetString());
2372        if (op.IsFound()) {
2373            JSHandle<JSTaggedValue> getter = op.FastGetValue();
2374            if (!getter->IsCallable() && !getter->IsUndefined()) {
2375                THROW_TYPE_ERROR(thread, "getter not callable or undefined");
2376            }
2377            desc.SetGetter(getter);
2378        }
2379    }
2380
2381    // 19. Let hasSet be HasProperty(Obj, "set").
2382    {
2383        ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetSetString());
2384        if (op.IsFound()) {
2385            JSHandle<JSTaggedValue> setter = op.FastGetValue();
2386            if (!setter->IsCallable() && !setter->IsUndefined()) {
2387                THROW_TYPE_ERROR(thread, "setter not callable or undefined");
2388            }
2389            desc.SetSetter(setter);
2390        }
2391    }
2392
2393    // 22. If either desc.[[Get]] or desc.[[Set]] is present, then
2394    if (desc.IsAccessorDescriptor()) {
2395        // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, throw a TypeError exception.
2396        if (desc.HasValue() || desc.HasWritable()) {
2397            THROW_TYPE_ERROR(thread, "either desc.[[Value]] or desc.[[Writable]] is present");
2398        }
2399    }
2400    // 23. Return desc.
2401}
2402
2403const CString JSObject::ExtractConstructorAndRecordName(JSThread *thread, TaggedObject *obj, bool noAllocate,
2404                                                        bool *isCallGetter)
2405{
2406    CString result = "";
2407    const GlobalEnvConstants *globalConst = thread->GlobalConstants();
2408
2409    JSHandle<JSTaggedValue> contructorKey = globalConst->GetHandledConstructorString();
2410    JSTaggedValue objConstructor = ObjectFastOperator::GetPropertyByName(thread, JSTaggedValue(obj),
2411                                                                         contructorKey.GetTaggedValue(), noAllocate,
2412                                                                         isCallGetter);
2413    if (*isCallGetter) {
2414        return "JSObject";
2415    }
2416
2417    if (!objConstructor.IsJSFunction()) {
2418        return "JSObject";
2419    }
2420
2421    JSFunctionBase *func = JSFunctionBase::Cast(objConstructor.GetTaggedObject());
2422    Method *method = Method::Cast(func->GetMethod().GetTaggedObject());
2423    MethodLiteral *methodLiteral = method->GetMethodLiteral();
2424    if (methodLiteral == nullptr) {
2425        return "JSObject";
2426    }
2427    const JSPandaFile *jsPandaFile = method->GetJSPandaFile();
2428    panda_file::File::EntityId methodId = methodLiteral->GetMethodId();
2429    const CString &nameStr = MethodLiteral::ParseFunctionNameToCString(jsPandaFile, methodId);
2430    const CString &moduleStr = method->GetRecordNameStr();
2431
2432    if (!moduleStr.empty()) {
2433        result.append(moduleStr).append(" ");
2434    }
2435    if (nameStr.empty()) {
2436        result.append("JSObject");
2437    } else {
2438        result.append(nameStr);
2439    }
2440    DebugInfoExtractor *debugExtractor =
2441        JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
2442    if (debugExtractor == nullptr) {
2443        return result;
2444    }
2445    int32_t line = debugExtractor->GetFristLine(methodId);
2446    std::string fileName = debugExtractor->GetSourceFile(methodId);
2447    return result.append("(").append(fileName).append(std::to_string(line)).append(")");
2448}
2449
2450JSHandle<JSTaggedValue> JSObject::SpeciesConstructor(JSThread *thread, const JSHandle<JSObject> &obj,
2451                                                     const JSHandle<JSTaggedValue> &defaultConstructor)
2452{
2453    const GlobalEnvConstants *globalConst = thread->GlobalConstants();
2454    // Assert: Type(O) is Object.
2455    ASSERT_PRINT(obj->IsECMAObject(), "obj must be js object");
2456
2457    // Let C be Get(O, "constructor").
2458    JSHandle<JSTaggedValue> contructorKey = globalConst->GetHandledConstructorString();
2459    JSHandle<JSTaggedValue> objConstructor(JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(obj),
2460        contructorKey).GetValue());
2461    // ReturnIfAbrupt(C).
2462    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
2463    return SlowSpeciesConstructor(thread, objConstructor, defaultConstructor);
2464}
2465
2466JSHandle<JSTaggedValue> JSObject::SlowSpeciesConstructor(JSThread *thread,
2467                                                         const JSHandle<JSTaggedValue> &objConstructor,
2468                                                         const JSHandle<JSTaggedValue> &defaultConstructor)
2469{
2470    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
2471    if (objConstructor->IsUndefined()) {
2472        return defaultConstructor;
2473    }
2474    // If Type(C) is not Object, throw a TypeError exception.
2475    if (!objConstructor->IsECMAObject()) {
2476        THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is not Object",
2477                                    JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
2478    }
2479    // Let S be Get(C, @@species).
2480    JSHandle<JSTaggedValue> speciesSymbol = env->GetSpeciesSymbol();
2481    JSHandle<JSTaggedValue> speciesConstructor = GetProperty(thread, objConstructor, speciesSymbol).GetValue();
2482    // ReturnIfAbrupt(S).
2483    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
2484    // If S is either undefined or null, return defaultConstructor.
2485    if (speciesConstructor->IsUndefined() || speciesConstructor->IsNull()) {
2486        return defaultConstructor;
2487    }
2488    // If IsConstructor(S) is true, return S.
2489    if (speciesConstructor->IsConstructor()) {
2490        return speciesConstructor;
2491    }
2492    // Throw a TypeError exception.
2493    THROW_TYPE_ERROR_AND_RETURN(thread, "Is not Constructor",
2494                                JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
2495    return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception());
2496}
2497
2498// 6.2.4.6 CompletePropertyDescriptor ( Desc )
2499void PropertyDescriptor::CompletePropertyDescriptor(const JSThread *thread, PropertyDescriptor &desc)
2500{
2501    // 1. ReturnIfAbrupt(Desc).
2502    // 2. Assert: Desc is a Property Descriptor
2503    // 3. Let like be Record{[[Value]]: undefined, [[Writable]]: false, [[Get]]: undefined, [[Set]]: undefined,
2504    // [[Enumerable]]: false, [[Configurable]]: false}.
2505    // 4. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then
2506    if (!desc.IsAccessorDescriptor()) {
2507        // a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to like.[[Value]].
2508        // b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]] to like.[[Writable]].
2509        if (!desc.HasValue()) {
2510            desc.SetValue(JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
2511        }
2512        if (!desc.HasWritable()) {
2513            desc.SetWritable(false);
2514        }
2515    } else {
2516        // a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to like.[[Get]].
2517        // b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to like.[[Set]].
2518        // Default value of Get and Set is undefined.
2519    }
2520    // 6. If Desc does not have an [[Enumerable]] field, set Desc.[[Enumerable]] to like.[[Enumerable]].
2521    // 7. If Desc does not have a [[Configurable]] field, set Desc.[[Configurable]] to like.[[Configurable]].
2522    if (!desc.HasEnumerable()) {
2523        desc.SetEnumerable(false);
2524    }
2525    if (!desc.HasConfigurable()) {
2526        desc.SetConfigurable(false);
2527    }
2528}
2529
2530// static
2531// When receiver has no elements and there is no enum cache and elements on receiver's prototype chain,
2532// the enum cache is a simple enum cache.
2533// When receiver and receiver's prototype chain have no elements, and the prototype is not modified,
2534// the enum cache is a enum cache with protochain
2535bool JSObject::IsSimpleEnumCacheValid(JSTaggedValue receiver)
2536{
2537    DISALLOW_GARBAGE_COLLECTION;
2538    uint32_t numOfElements = JSObject::Cast(receiver.GetTaggedObject())->GetNumberOfElements();
2539    if (numOfElements > 0) {
2540        return false;
2541    }
2542
2543    JSTaggedValue current = JSObject::GetPrototype(receiver);
2544    while (current.IsHeapObject()) {
2545        JSObject *currentObj = JSObject::Cast(current.GetTaggedObject());
2546        uint32_t numOfCurrentElements = currentObj->GetNumberOfElements();
2547        if (numOfCurrentElements > 0) {
2548            return false;
2549        }
2550        JSHClass *hclass = currentObj->GetJSHClass();
2551        JSTaggedValue protoEnumCache = hclass->GetEnumCache();
2552        if (!protoEnumCache.IsUndefined()) {
2553            return false;
2554        }
2555        current = JSObject::GetPrototype(current);
2556    }
2557    return true;
2558}
2559
2560bool JSObject::IsEnumCacheWithProtoChainInfoValid(JSTaggedValue receiver)
2561{
2562    DISALLOW_GARBAGE_COLLECTION;
2563    // check elements of receiver
2564    uint32_t numOfElements = JSObject::Cast(receiver.GetTaggedObject())->GetNumberOfElements();
2565    if (numOfElements > 0) {
2566        return false;
2567    }
2568    // check protochain keys
2569    JSTaggedValue proto = JSObject::GetPrototype(receiver);
2570    if (!proto.IsECMAObject()) {
2571        return false;
2572    }
2573    JSTaggedValue protoChangeMarker = proto.GetTaggedObject()->GetClass()->GetProtoChangeMarker();
2574    if (!protoChangeMarker.IsProtoChangeMarker()) {
2575        return false;
2576    }
2577    if (ProtoChangeMarker::Cast(protoChangeMarker.GetTaggedObject())->GetHasChanged()) {
2578        return false;
2579    }
2580    // check protochain elements
2581    JSTaggedValue current = proto;
2582    while (current.IsHeapObject()) {
2583        JSObject *currentObj = JSObject::Cast(current.GetTaggedObject());
2584        uint32_t numOfCurrentElements = currentObj->GetNumberOfElements();
2585        if (numOfCurrentElements > 0) {
2586            return false;
2587        }
2588        current = JSObject::GetPrototype(current);
2589    }
2590    return true;
2591}
2592
2593JSTaggedValue JSObject::TryGetEnumCache(JSThread *thread, JSTaggedValue obj)
2594{
2595    if (obj.IsSlowKeysObject() || obj.GetTaggedObject()->GetClass()->IsDictionaryMode()) {
2596        return JSTaggedValue::Undefined();
2597    }
2598    JSTaggedValue enumCache = obj.GetTaggedObject()->GetClass()->GetEnumCache();
2599    EnumCacheKind kind = JSObject::GetEnumCacheKind(thread, enumCache);
2600    bool isEnumCacheValid = false;
2601    switch (kind) {
2602        case EnumCacheKind::SIMPLE:
2603            isEnumCacheValid = IsSimpleEnumCacheValid(obj);
2604            break;
2605        case EnumCacheKind::PROTOCHAIN:
2606            isEnumCacheValid = IsEnumCacheWithProtoChainInfoValid(obj);
2607            break;
2608        default:
2609            break;
2610    }
2611    if (!isEnumCacheValid) {
2612        return JSTaggedValue::Undefined();
2613    }
2614    return enumCache;
2615}
2616
2617// 13.7.5.15 EnumerateObjectProperties ( O )
2618JSHandle<JSForInIterator> JSObject::EnumerateObjectProperties(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
2619{
2620    JSHandle<JSTaggedValue> object;
2621    if (obj->IsString()) {
2622        JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2623        object = JSHandle<JSTaggedValue>::Cast(JSPrimitiveRef::StringCreate(thread, obj, undefined));
2624    } else {
2625        object = JSTaggedValue::ToPrototypeOrObj(thread, obj);
2626    }
2627
2628    JSMutableHandle<JSTaggedValue> keys(thread, JSTaggedValue::Undefined());
2629    JSMutableHandle<JSTaggedValue> cachedHclass(thread, JSTaggedValue::Undefined());
2630    if (object->IsNull() || object->IsUndefined()) {
2631        JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2632        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2633        keys.Update(factory->EmptyArray());
2634        return factory->NewJSForinIterator(undefined, keys, cachedHclass);
2635    }
2636    keys.Update(TryGetEnumCache(thread, object.GetTaggedValue()));
2637    if (!keys->IsUndefined()) {
2638        cachedHclass.Update(JSTaggedValue(JSHandle<JSObject>::Cast(object)->GetJSHClass()));
2639        return thread->GetEcmaVM()->GetFactory()->NewJSForinIterator(object, keys, cachedHclass);
2640    }
2641    return LoadEnumerateProperties(thread, object);
2642}
2643
2644JSHandle<JSForInIterator> JSObject::LoadEnumerateProperties(JSThread *thread, const JSHandle<JSTaggedValue> &object)
2645{
2646    PropertyAccessor accessor(thread, object);
2647    JSHandle<JSTaggedValue> fastKeys = accessor.GetKeysFast();
2648    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSForInIterator, thread);
2649    JSMutableHandle<JSTaggedValue> keys(thread, JSTaggedValue::Undefined());
2650    JSMutableHandle<JSTaggedValue> cachedHclass(thread, JSTaggedValue::Undefined());
2651    if (fastKeys->IsUndefined()) {
2652        keys.Update(accessor.GetKeysSlow());
2653        RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSForInIterator, thread);
2654    } else {
2655        keys.Update(fastKeys);
2656        cachedHclass.Update(accessor.GetCachedHclass());
2657    }
2658    return thread->GetEcmaVM()->GetFactory()->NewJSForinIterator(object, keys, cachedHclass);
2659}
2660
2661void JSObject::DefinePropertyByLiteral(JSThread *thread, const JSHandle<JSObject> &obj,
2662                                       const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
2663                                       bool useForClass)
2664{
2665    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
2666    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2667    PropertyAttributes attr = useForClass ? PropertyAttributes::Default(true, false, true)
2668                                          : PropertyAttributes::Default();
2669
2670    if (value->IsAccessorData()) {
2671        attr.SetIsAccessor(true);
2672    }
2673
2674    uint32_t index = 0;
2675    if (UNLIKELY(JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
2676        AddElementInternal(thread, obj, index, value, attr);
2677        return;
2678    }
2679    LOG_ECMA(FATAL) << "this branch is unreachable";
2680    UNREACHABLE();
2681}
2682
2683void JSObject::DefineSetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2684                            const JSHandle<JSTaggedValue> &value)
2685{
2686    ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2687    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2688    ObjectOperator op(thread, obj, key, OperatorType::OWN);
2689    ASSERT(op.IsFound());
2690    op.DefineSetter(value);
2691}
2692
2693void JSObject::DefineGetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2694                            const JSHandle<JSTaggedValue> &value)
2695{
2696    ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2697    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2698    ObjectOperator op(thread, obj, key, OperatorType::OWN);
2699    ASSERT(op.IsFound());
2700    op.DefineGetter(value);
2701}
2702
2703JSHandle<JSObject> JSObject::CreateObjectFromProperties(const JSThread *thread, const JSHandle<TaggedArray> &properties,
2704                                                        JSTaggedValue ihcVal)
2705{
2706    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2707    size_t length = properties->GetLength();
2708    uint32_t propsLen = 0;
2709    for (size_t i = 0; i < length; i += 2) {  // 2: skip a pair of key and value
2710        if (properties->Get(i).IsHole()) {
2711            break;
2712        }
2713        propsLen++;
2714    }
2715    if (propsLen <= PropertyAttributes::MAX_FAST_PROPS_CAPACITY) {
2716        JSHandle<JSHClass> hclass;
2717        bool isLiteral = false;
2718        if (ihcVal.IsJSHClass()) {
2719            hclass = JSHandle<JSHClass>(thread, ihcVal);
2720        } else {
2721            hclass = factory->GetObjectLiteralHClass(properties, propsLen);
2722            isLiteral = true;
2723        }
2724        if (hclass->IsTS()) {
2725            if (CheckPropertiesForRep(properties, propsLen, hclass)) {
2726                return CreateObjectFromPropertiesByIHClass(thread, properties, propsLen, hclass);
2727            } else if (!isLiteral) {
2728                hclass = factory->GetObjectLiteralHClass(properties, propsLen);
2729                // if check failed, get literal object again
2730                return CreateObjectFromPropertiesByIHClass(thread, properties, propsLen, hclass);
2731            }
2732        }
2733        return CreateObjectFromProperties(thread, hclass, properties, propsLen);
2734    } else {
2735        JSHandle<JSObject> obj = factory->NewEmptyJSObject(0); // 0: no inline field
2736        ElementsKind oldKind = obj->GetJSHClass()->GetElementsKind();
2737        JSHClass::TransitionToDictionary(thread, obj);
2738        JSObject::TryMigrateToGenericKindForJSObject(thread, obj, oldKind);
2739
2740        JSMutableHandle<NameDictionary> dict(
2741            thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(propsLen)));
2742        JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
2743        JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
2744        for (size_t i = 0; i < propsLen; i++) {
2745            PropertyAttributes attr = PropertyAttributes::Default();
2746            // 2: literal contains a pair of key-value
2747            valueHandle.Update(properties->Get(i * 2 + 1));
2748            // 2: literal contains a pair of key-value
2749            keyHandle.Update(properties->Get(i * 2));
2750            JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
2751            dict.Update(newDict);
2752        }
2753        obj->SetProperties(thread, dict);
2754        return obj;
2755    }
2756}
2757
2758JSHandle<JSObject> JSObject::CreateObjectFromProperties(const JSThread *thread,
2759                                                        const JSHandle<JSHClass> &hclass,
2760                                                        const JSHandle<TaggedArray> &properties,
2761                                                        uint32_t propsLen)
2762{
2763    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2764    JSHandle<JSObject> obj = factory->NewOldSpaceObjLiteralByHClass(hclass);
2765    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
2766
2767    if (thread->IsPGOProfilerEnable()) {
2768        // PGO need to track TrackType
2769        JSHClass *oldHC = obj->GetJSHClass();
2770        LayoutInfo *layoutInfo = LayoutInfo::Cast(oldHC->GetLayout().GetTaggedObject());
2771        for (size_t i = 0; i < propsLen; i++) {
2772            auto value = properties->Get(i * 2 + 1);
2773            auto attr = layoutInfo->GetAttr(i);
2774            if (attr.UpdateTrackType(value) && !oldHC->IsJSShared()) {
2775                layoutInfo->SetNormalAttr(thread, i, attr);
2776            }
2777            obj->SetPropertyInlinedProps(thread, i, value);
2778        }
2779    } else {
2780        for (size_t i = 0; i < propsLen; i++) {
2781            // 2: literal contains a pair of key-value
2782            obj->SetPropertyInlinedProps(thread, i, properties->Get(i * 2 + 1));
2783        }
2784    }
2785    return obj;
2786}
2787
2788JSHandle<JSObject> JSObject::CreateObjectFromPropertiesByIHClass(const JSThread *thread,
2789                                                                 const JSHandle<TaggedArray> &properties,
2790                                                                 uint32_t propsLen,
2791                                                                 const JSHandle<JSHClass> &ihc)
2792{
2793    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2794
2795    JSHandle<JSObject> obj = factory->NewOldSpaceObjLiteralByHClass(ihc);
2796    ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
2797    auto layout = LayoutInfo::Cast(ihc->GetLayout().GetTaggedObject());
2798    for (size_t i = 0; i < propsLen; i++) {
2799        auto attr = layout->GetAttr(i);
2800        auto value = JSObject::ConvertValueWithRep(attr, properties->Get(i * 2 + 1));
2801        ASSERT(value.first);
2802        obj->SetPropertyInlinedPropsWithRep(thread, i, value.second);
2803    }
2804    return obj;
2805}
2806
2807bool JSObject::CheckPropertiesForRep(
2808    const JSHandle<TaggedArray> &properties, uint32_t propsLen, const JSHandle<JSHClass> &ihc)
2809{
2810    auto layout = LayoutInfo::Cast(ihc->GetLayout().GetTaggedObject());
2811    for (size_t i = 0; i < propsLen; i++) {
2812        auto attr = layout->GetAttr(i);
2813        auto value = JSObject::ConvertValueWithRep(attr, properties->Get(i * 2 + 1));
2814        // If value.first is false, indicating that value cannot be converted to the expected value of
2815        // representation. For example, the representation is INT, but the value type is string.
2816        if (!value.first) {
2817            return false;
2818        }
2819    }
2820    return true;
2821}
2822
2823void JSObject::AddAccessor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2824                           const JSHandle<AccessorData> &value, PropertyAttributes attr)
2825{
2826    ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2827    ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2828    ASSERT_PRINT(attr.IsAccessor(), "Attr is not AccessorData");
2829    ObjectOperator op(thread, obj, key, OperatorType::OWN);
2830    ASSERT(!op.IsFound());
2831    op.AddProperty(JSHandle<JSObject>::Cast(obj), JSHandle<JSTaggedValue>(value), attr);
2832}
2833
2834bool JSObject::UpdatePropertyInDictionary(const JSThread *thread, JSTaggedValue key, JSTaggedValue value)
2835{
2836    [[maybe_unused]] DisallowGarbageCollection noGc;
2837    NameDictionary *dict = NameDictionary::Cast(GetProperties().GetTaggedObject());
2838    int entry = dict->FindEntry(key);
2839    if (entry == -1) {
2840        return false;
2841    }
2842    dict->UpdateValue(thread, entry, value);
2843    return true;
2844}
2845
2846void JSObject::TrimInlinePropsSpace(const JSThread *thread, const JSHandle<JSObject> &object,
2847                                    uint32_t numberInlinedProps)
2848{
2849    if (numberInlinedProps > 0) {
2850        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2851        uint32_t newSize = object->GetClass()->GetObjectSize();
2852        size_t trimBytes = numberInlinedProps * JSTaggedValue::TaggedTypeSize();
2853        factory->FillFreeObject(ToUintPtr(*object) + newSize, trimBytes, RemoveSlots::YES, ToUintPtr(*object));
2854    }
2855}
2856
2857// The hash field may be a hash value, FunctionExtraInfo(JSNativePointer) or TaggedArray
2858void ECMAObject::SetHash(const JSThread *thread, int32_t hash, const JSHandle<ECMAObject> &obj)
2859{
2860    JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(*obj, HASH_OFFSET);
2861    JSTaggedValue value(hashField);
2862    if (value.IsHeapObject()) {
2863        // Hash position reserve in advance.
2864        if (value.IsTaggedArray()) {
2865            TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2866            array->Set(thread, array->GetExtraLength() + HASH_INDEX, JSTaggedValue(hash));
2867        } else if (value.IsNativePointer()) { // FunctionExtraInfo
2868            JSHandle<TaggedArray> newArray =
2869                thread->GetEcmaVM()->GetFactory()->NewTaggedArray(RESOLVED_MAX_SIZE);
2870            newArray->SetExtraLength(0);
2871            newArray->Set(thread, HASH_INDEX, JSTaggedValue(hash));
2872            newArray->Set(thread, FUNCTION_EXTRA_INDEX, value);
2873            Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2874        } else {
2875            LOG_ECMA(FATAL) << "this branch is unreachable";
2876            UNREACHABLE();
2877        }
2878    } else {
2879        Barriers::SetPrimitive<JSTaggedType>(*obj, HASH_OFFSET, JSTaggedValue(hash).GetRawData());
2880    }
2881}
2882
2883int32_t ECMAObject::GetHash() const
2884{
2885    JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2886    JSTaggedValue value(hashField);
2887    if (value.IsHeapObject()) {
2888        if (value.IsTaggedArray()) {
2889            TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2890            return array->Get(array->GetExtraLength() + HASH_INDEX).GetInt();
2891        } else {
2892            // Default is 0
2893            return 0;
2894        }
2895    }
2896    return value.GetInt();
2897}
2898
2899bool ECMAObject::HasHash() const
2900{
2901    JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2902    JSTaggedValue value(hashField);
2903    if (value.IsInt() && value.GetInt() == 0) {
2904        return false;
2905    }
2906    return true;
2907}
2908
2909void *ECMAObject::GetNativePointerField(int32_t index) const
2910{
2911    JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2912    JSTaggedValue value(hashField);
2913    if (value.IsTaggedArray()) {
2914        auto array = TaggedArray::Cast(value);
2915        if (static_cast<int32_t>(array->GetExtraLength()) > index) {
2916            auto jsValue = array->Get(index);
2917            if (UNLIKELY(!jsValue.IsJSNativePointer())) {
2918                LOG_FULL(ERROR) << "jsValue is not js native pointer";
2919                return nullptr;
2920            }
2921            auto pointer = JSNativePointer::Cast(jsValue.GetTaggedObject());
2922            return pointer->GetExternalPointer();
2923        }
2924    }
2925    return nullptr;
2926}
2927
2928void ECMAObject::SetNativePointerField(const JSThread *thread, int32_t index, void *nativePointer,
2929    const NativePointerCallback &callBack, void *data, size_t nativeBindingsize, Concurrent isConcurrent)
2930{
2931    JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2932    JSTaggedValue value(hashField);
2933    if (value.IsTaggedArray()) {
2934        JSHandle<TaggedArray> array(thread, value);
2935        if (static_cast<int32_t>(array->GetExtraLength()) > index) {
2936            EcmaVM *vm = thread->GetEcmaVM();
2937            JSHandle<JSTaggedValue> current = JSHandle<JSTaggedValue>(thread, array->Get(thread, index));
2938            JSHandle<JSTaggedValue> obj(thread, this);
2939            if (!current->IsHole() && nativePointer == nullptr) {
2940                // Try to remove native pointer if exists.
2941                vm->RemoveFromNativePointerList(*JSHandle<JSNativePointer>(current));
2942                array->Set(thread, index, JSTaggedValue::Hole());
2943            } else if (obj->IsJSShared()) {
2944                JSHandle<JSNativePointer> pointer =
2945                    vm->GetFactory()->NewSJSNativePointer(nativePointer, callBack, data, false, nativeBindingsize);
2946                array->Set(thread, index, pointer.GetTaggedValue());
2947            } else {
2948                JSHandle<JSNativePointer> pointer = vm->GetFactory()->NewJSNativePointer(
2949                    nativePointer, callBack, data, false, nativeBindingsize, isConcurrent);
2950                array->Set(thread, index, pointer.GetTaggedValue());
2951            }
2952        }
2953    }
2954}
2955
2956int32_t ECMAObject::GetNativePointerFieldCount() const
2957{
2958    int32_t len = 0;
2959    JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2960    JSTaggedValue value(hashField);
2961    if (value.IsTaggedArray()) {
2962        TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2963        len = static_cast<int32_t>(array->GetExtraLength());
2964    }
2965    return len;
2966}
2967
2968void ECMAObject::SetNativePointerFieldCount(const JSThread *thread, int32_t count)
2969{
2970    if (count == 0) {
2971        return;
2972    }
2973    JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2974    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(hashField));
2975    JSHandle<ECMAObject> obj(thread, this);
2976    JSHandle<JSTaggedValue> object(obj);
2977    bool isShared = object->IsJSShared();
2978    if (value->IsHeapObject()) {
2979        if (value->IsTaggedArray()) {
2980            JSHandle<TaggedArray> array(value);
2981            // Native Pointer field count is fixed.
2982            if (array->GetExtraLength() == 0) {
2983                JSHandle<TaggedArray> newArray =
2984                    isShared ? thread->GetEcmaVM()->GetFactory()->NewSTaggedArray(count + RESOLVED_MAX_SIZE)
2985                             : thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + RESOLVED_MAX_SIZE);
2986                newArray->SetExtraLength(count);
2987                newArray->Set(thread, count + HASH_INDEX, array->Get(HASH_INDEX));
2988                newArray->Set(thread, count + FUNCTION_EXTRA_INDEX, array->Get(FUNCTION_EXTRA_INDEX));
2989                Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2990            }
2991        } else if (value->IsJSNativePointer()) {
2992            JSHandle<TaggedArray> newArray =
2993                isShared ? thread->GetEcmaVM()->GetFactory()->NewSTaggedArray(count + RESOLVED_MAX_SIZE)
2994                         : thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + RESOLVED_MAX_SIZE);
2995            newArray->SetExtraLength(count);
2996            newArray->Set(thread, count + HASH_INDEX, JSTaggedValue(0));
2997            newArray->Set(thread, count + FUNCTION_EXTRA_INDEX, value);
2998            Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2999        } else {
3000            LOG_ECMA(FATAL) << "this branch is unreachable";
3001            UNREACHABLE();
3002        }
3003    } else {
3004        JSHandle<TaggedArray> newArray = isShared ? thread->GetEcmaVM()->GetFactory()->NewSTaggedArray(count + 1)
3005                                                  : thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + 1);
3006        newArray->SetExtraLength(count);
3007        newArray->Set(thread, count + HASH_INDEX, value);
3008        Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
3009    }
3010}
3011
3012bool JSObject::ElementsAndPropertiesIsEmpty() const
3013{
3014    if (TaggedArray::Cast(GetElements().GetTaggedObject())->GetLength() == 0 &&
3015        TaggedArray::Cast(GetProperties().GetTaggedObject())->GetLength() == 0) {
3016        return true;
3017    }
3018    return false;
3019}
3020
3021void JSObject::TryMigrateToGenericKindForJSObject(const JSThread *thread, const JSHandle<JSObject> &obj,
3022                                                  const ElementsKind oldKind)
3023{
3024    if (obj->IsJSArray() && HasMutantTaggedArrayElements(obj)) {
3025        Elements::MigrateArrayWithKind(thread, obj, oldKind, ElementsKind::GENERIC);
3026    }
3027}
3028}  // namespace panda::ecmascript
3029