1/*
2 * Copyright (c) 2021 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/object_operator.h"
17
18#include "ecmascript/global_dictionary-inl.h"
19#include "ecmascript/js_primitive_ref.h"
20#include "ecmascript/object_fast_operator-inl.h"
21#include "ecmascript/property_detector-inl.h"
22
23namespace panda::ecmascript {
24void ObjectOperator::HandleKey(const JSHandle<JSTaggedValue> &key)
25{
26    if (key->IsInt()) {
27        int32_t keyInt = key->GetInt();
28        if (keyInt >= 0) {
29            elementIndex_ = static_cast<uint32_t>(keyInt);
30            return;
31        }
32        key_ = JSHandle<JSTaggedValue>::Cast(base::NumberHelper::NumberToString(thread_, JSTaggedValue(keyInt)));
33        return;
34    }
35
36    if (key->IsString()) {
37        keyFromStringType_ = true;
38        uint32_t index = 0;
39        if (JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index)) {
40            ASSERT(index < JSObject::MAX_ELEMENT_INDEX);
41            elementIndex_ = index;
42            return;
43        }
44        if (EcmaStringAccessor(key->GetTaggedObject()).IsInternString()) {
45            key_ = key;
46            return;
47        }
48        key_ = JSHandle<JSTaggedValue>(thread_, thread_->GetEcmaVM()->GetFactory()->InternString(key));
49        return;
50    }
51
52    if (key->IsDouble()) {
53        double number = key->GetDouble();
54        if (number >= 0 && number < JSObject::MAX_ELEMENT_INDEX) {
55            auto integer = static_cast<uint32_t>(number);
56            if (integer == number) {
57                elementIndex_ = static_cast<uint32_t>(number);
58                return;
59            }
60        }
61        key_ = JSHandle<JSTaggedValue>::Cast(base::NumberHelper::NumberToString(thread_, key.GetTaggedValue()));
62        if (!EcmaStringAccessor(key_.GetTaggedValue()).IsInternString()) {
63                key_ = JSHandle<JSTaggedValue>(thread_, thread_->GetEcmaVM()->GetFactory()->InternString(key_));
64        }
65        return;
66    }
67
68    if (key->IsSymbol()) {
69        key_ = key;
70        return;
71    }
72
73    JSHandle<JSTaggedValue> keyHandle(thread_, JSTaggedValue::ToPrimitive(thread_, key, PREFER_STRING));
74    RETURN_IF_ABRUPT_COMPLETION(thread_);
75    if (key->IsSymbol()) {
76        key_ = keyHandle;
77        return;
78    }
79    key_ = JSHandle<JSTaggedValue>(thread_,
80                                   thread_->GetEcmaVM()->GetFactory()->InternString(
81                                       JSHandle<JSTaggedValue>::Cast(JSTaggedValue::ToString(thread_, keyHandle))));
82}
83
84void ObjectOperator::UpdateHolder()
85{
86    if (holder_->IsString() && (GetThroughElement() || GetStringLength())) {
87        JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
88        holder_.Update(JSPrimitiveRef::StringCreate(thread_, holder_, undefined).GetTaggedValue());
89    } else {
90        if (holder_->IsString() || holder_->IsNumber()) {
91            SetIsOnPrototype(true);
92        }
93        holder_.Update(JSTaggedValue::ToPrototypeOrObj(thread_, holder_).GetTaggedValue());
94    }
95}
96
97void ObjectOperator::UpdateIsTSHClass()
98{
99    if (!holder_->IsECMAObject()) {
100        SetIsTSHClass(false);
101        return;
102    }
103    auto hclass = JSHandle<JSObject>::Cast(holder_)->GetClass();
104    if (hclass->IsTS()) {
105        SetIsTSHClass(true);
106    }
107}
108
109void ObjectOperator::StartLookUp(OperatorType type)
110{
111    UpdateHolder();
112
113    if (type == OperatorType::OWN) {
114        LookupPropertyInHolder();
115    } else {
116        LookupProperty();
117    }
118}
119
120void ObjectOperator::StartGlobalLookUp(OperatorType type)
121{
122    UpdateHolder();
123
124    if (type == OperatorType::OWN) {
125        GlobalLookupPropertyInHolder();
126    } else {
127        GlobalLookupProperty();
128    }
129}
130
131ObjectOperator::ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &key, OperatorType type)
132    : thread_(thread),
133      holder_(thread, thread->GetEcmaVM()->GetGlobalEnv()->GetGlobalObject()),
134      receiver_(thread, thread->GetEcmaVM()->GetGlobalEnv()->GetGlobalObject())
135{
136    HandleKey(key);
137    StartGlobalLookUp(type);
138}
139
140ObjectOperator::ObjectOperator(JSThread *thread, const JSHandle<JSObject> &holder, const JSHandle<JSTaggedValue> &key,
141                               OperatorType type)
142    : thread_(thread), holder_(thread, holder.GetTaggedValue()), receiver_(thread, holder.GetTaggedValue())
143{
144    HandleKey(key);
145    StartLookUp(type);
146}
147
148ObjectOperator::ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder,
149                               const JSHandle<JSTaggedValue> &key, OperatorType type)
150    : thread_(thread), holder_(thread, holder.GetTaggedValue()), receiver_(thread, holder.GetTaggedValue())
151{
152    HandleKey(key);
153    StartLookUp(type);
154}
155
156ObjectOperator::ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder, uint32_t index,
157                               OperatorType type)
158    : thread_(thread),
159      holder_(thread, holder.GetTaggedValue()),
160      receiver_(thread, holder.GetTaggedValue()),
161      elementIndex_(index)
162{
163    StartLookUp(type);
164}
165
166ObjectOperator::ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder,
167                               const JSHandle<JSTaggedValue> &receiver, const JSHandle<JSTaggedValue> &key,
168                               OperatorType type)
169    : thread_(thread), holder_(thread, holder.GetTaggedValue()), receiver_(thread, receiver.GetTaggedValue())
170{
171    SetHasReceiver(true);
172    HandleKey(key);
173    StartLookUp(type);
174}
175
176// op for fast path
177ObjectOperator::ObjectOperator(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name,
178                               OperatorType type)
179    : thread_(thread), holder_(thread, receiver), receiver_(thread, receiver), key_(thread, name)
180{
181    ASSERT(name.IsStringOrSymbol());
182    StartLookUp(type);
183}
184JSHandle<JSTaggedValue> ObjectOperator::FastGetValue()
185{
186    ASSERT(IsFound() && !value_.IsEmpty());
187    if (value_->IsPropertyBox()) {
188        value_.Update(PropertyBox::Cast(value_->GetTaggedObject())->GetValue());
189    }
190    if (!IsAccessorDescriptor()) {
191        return value_;
192    }
193    AccessorData *accessor = AccessorData::Cast(value_->GetTaggedObject());
194    ASSERT(!accessor->IsInternal());
195    // 8. Return Call(getter, Receiver).
196    return JSHandle<JSTaggedValue>(thread_, JSObject::CallGetter(thread_, accessor, receiver_));
197}
198ObjectOperator::ObjectOperator(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name,
199                               const PropertyAttributes &attr)
200    : thread_(thread), receiver_(thread, receiver), key_(thread, name)
201{
202    SetAttr(attr);
203}
204void ObjectOperator::FastAdd(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name,
205                             const JSHandle<JSTaggedValue> &value, const PropertyAttributes &attr)
206{
207    ObjectOperator op(thread, receiver, name, attr);
208    op.AddPropertyInternal(value);
209}
210
211// static
212void ObjectOperator::UpdateDetectorOnSetPrototype(const JSThread *thread, JSTaggedValue receiver)
213{
214    // skip env prepare
215    if (!thread->IsReadyToUpdateDetector()) {
216        return;
217    }
218    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
219    JSHClass *hclass = receiver.GetTaggedObject()->GetClass();
220    JSType type = hclass->GetObjectType();
221    switch (type) {
222        case JSType::JS_REG_EXP: {
223            if (PropertyDetector::IsRegExpReplaceDetectorValid(env)) {
224                PropertyDetector::InvalidateRegExpReplaceDetector(env);
225            }
226            if (PropertyDetector::IsRegExpFlagsDetectorValid(env)) {
227                PropertyDetector::InvalidateRegExpFlagsDetector(env);
228            }
229            return;
230        }
231        case JSType::JS_MAP: {
232            if (PropertyDetector::IsMapIteratorDetectorValid(env)) {
233                PropertyDetector::InvalidateMapIteratorDetector(env);
234            }
235            return;
236        }
237        case JSType::JS_SET: {
238            if (PropertyDetector::IsSetIteratorDetectorValid(env)) {
239                PropertyDetector::InvalidateSetIteratorDetector(env);
240            }
241            return;
242        }
243        case JSType::JS_PRIMITIVE_REF: {
244            if (JSPrimitiveRef::Cast(receiver.GetTaggedObject())->IsString() &&
245                PropertyDetector::IsStringIteratorDetectorValid(env)) {
246                PropertyDetector::InvalidateStringIteratorDetector(env);
247            }
248            return;
249        }
250        case JSType::JS_ARRAY: {
251            if (PropertyDetector::IsArrayIteratorDetectorValid(env)) {
252                PropertyDetector::InvalidateArrayIteratorDetector(env);
253            }
254            return;
255        }
256        case JSType::JS_INT8_ARRAY:
257        case JSType::JS_UINT8_ARRAY:
258        case JSType::JS_UINT8_CLAMPED_ARRAY:
259        case JSType::JS_INT16_ARRAY:
260        case JSType::JS_UINT16_ARRAY:
261        case JSType::JS_INT32_ARRAY:
262        case JSType::JS_UINT32_ARRAY:
263        case JSType::JS_FLOAT32_ARRAY:
264        case JSType::JS_FLOAT64_ARRAY:
265        case JSType::JS_BIGINT64_ARRAY:
266        case JSType::JS_BIGUINT64_ARRAY: {
267            if (PropertyDetector::IsTypedArrayIteratorDetectorValid(env)) {
268                PropertyDetector::InvalidateTypedArrayIteratorDetector(env);
269            }
270            if (PropertyDetector::IsTypedArraySpeciesProtectDetectorValid(env)) {
271                PropertyDetector::InvalidateTypedArraySpeciesProtectDetector(env);
272            }
273            return;
274        }
275        default:
276            break;
277    }
278
279    if (hclass->IsPrototype() &&
280        (receiver == env->GetTaggedInt8ArrayFunctionPrototype() ||
281         receiver == env->GetTaggedUint8ArrayFunctionPrototype() ||
282         receiver == env->GetTaggedUint8ClampedArrayFunctionPrototype() ||
283         receiver == env->GetTaggedInt16ArrayFunctionPrototype() ||
284         receiver == env->GetTaggedUint16ArrayFunctionPrototype() ||
285         receiver == env->GetTaggedInt32ArrayFunctionPrototype() ||
286         receiver == env->GetTaggedUint32ArrayFunctionPrototype() ||
287         receiver == env->GetTaggedFloat32ArrayFunctionPrototype() ||
288         receiver == env->GetTaggedFloat64ArrayFunctionPrototype() ||
289         receiver == env->GetTaggedBigInt64ArrayFunctionPrototype() ||
290         receiver == env->GetTaggedBigUint64ArrayFunctionPrototype()) &&
291         PropertyDetector::IsTypedArrayIteratorDetectorValid(env)) {
292        PropertyDetector::InvalidateTypedArrayIteratorDetector(env);
293        return;
294    }
295    if ((PropertyDetector::IsNumberStringNotRegexpLikeDetectorValid(env) &&
296        JSObject::Cast(receiver)->GetJSHClass()->IsPrototype() && receiver.IsJSPrimitive())) {
297        PropertyDetector::InvalidateNumberStringNotRegexpLikeDetector(env);
298        return;
299    }
300}
301
302void ObjectOperator::UpdateDetector()
303{
304    if (IsElement()) {
305        return;
306    }
307    ObjectOperator::UpdateDetector(thread_, holder_.GetTaggedValue(), key_.GetTaggedValue());
308}
309
310// static
311void ObjectOperator::UpdateDetector(const JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
312{
313    // skip env prepare
314    if (!thread->IsReadyToUpdateDetector()) {
315        return;
316    }
317    bool maybeDetector = IsDetectorName(thread, key);
318    if (!maybeDetector) {
319        return;
320    }
321    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
322    auto globalConst = thread->GlobalConstants();
323    if (key == env->GetTaggedReplaceSymbol() &&
324        (receiver.IsJSRegExp() || receiver == env->GetTaggedRegExpPrototype())) {
325        if (!PropertyDetector::IsRegExpReplaceDetectorValid(env)) {
326            return;
327        }
328        PropertyDetector::InvalidateRegExpReplaceDetector(env);
329    } else if (key == env->GetTaggedIteratorSymbol()) {
330        if (receiver.IsJSMap() || receiver == env->GetTaggedMapPrototype()) {
331            if (!PropertyDetector::IsMapIteratorDetectorValid(env)) {
332                return;
333            }
334            PropertyDetector::InvalidateMapIteratorDetector(env);
335        } else if (receiver.IsJSSet() || receiver == env->GetTaggedSetPrototype()) {
336            if (!PropertyDetector::IsSetIteratorDetectorValid(env)) {
337                return;
338            }
339            PropertyDetector::InvalidateSetIteratorDetector(env);
340        } else if ((receiver.IsJSPrimitiveRef() && JSPrimitiveRef::Cast(receiver.GetTaggedObject())->IsString()) ||
341                   receiver == env->GetTaggedStringPrototype()) {
342            if (!PropertyDetector::IsStringIteratorDetectorValid(env)) {
343                return;
344            }
345            PropertyDetector::InvalidateStringIteratorDetector(env);
346        } else if (receiver.IsJSArray() || receiver == env->GetTaggedArrayPrototype()) {
347            if (!PropertyDetector::IsArrayIteratorDetectorValid(env)) {
348                return;
349            }
350            PropertyDetector::InvalidateArrayIteratorDetector(env);
351        } else if (receiver.IsTypedArray() ||
352                   receiver == env->GetTaggedArrayPrototype() ||
353                   receiver == env->GetTaggedInt8ArrayFunctionPrototype() ||
354                   receiver == env->GetTaggedUint8ArrayFunctionPrototype() ||
355                   receiver == env->GetTaggedUint8ClampedArrayFunctionPrototype() ||
356                   receiver == env->GetTaggedInt16ArrayFunctionPrototype() ||
357                   receiver == env->GetTaggedUint16ArrayFunctionPrototype() ||
358                   receiver == env->GetTaggedInt32ArrayFunctionPrototype() ||
359                   receiver == env->GetTaggedUint32ArrayFunctionPrototype() ||
360                   receiver == env->GetTaggedFloat32ArrayFunctionPrototype() ||
361                   receiver == env->GetTaggedFloat64ArrayFunctionPrototype() ||
362                   receiver == env->GetTaggedBigInt64ArrayFunctionPrototype() ||
363                   receiver == env->GetTaggedBigUint64ArrayFunctionPrototype()) {
364            if (!PropertyDetector::IsTypedArrayIteratorDetectorValid(env)) {
365                return;
366            }
367            PropertyDetector::InvalidateTypedArrayIteratorDetector(env);
368        }
369    } else if (key == env->GetTaggedSpeciesSymbol()) {
370        if (receiver == env->GetTypedArrayFunction().GetTaggedValue()) {
371            if (!PropertyDetector::IsTypedArraySpeciesProtectDetectorValid(env)) {
372                return;
373            }
374            PropertyDetector::InvalidateTypedArraySpeciesProtectDetector(env);
375        }
376        if (receiver == env->GetRegExpFunction().GetTaggedValue()) {
377            if (!PropertyDetector::IsRegExpSpeciesDetectorValid(env)) {
378                return;
379            }
380            PropertyDetector::InvalidateRegExpSpeciesDetector(env);
381        }
382    } else if ((key == env->GetTaggedReplaceSymbol()) ||
383        (key == env->GetTaggedSplitSymbol()) ||
384        (key == env->GetTaggedMatchAllSymbol())) {
385        if (!PropertyDetector::IsNumberStringNotRegexpLikeDetectorValid(env)) {
386            return;
387        }
388        // check String.prototype or Number.prototype or Object.prototype
389        if ((JSObject::Cast(receiver)->GetJSHClass()->IsPrototype() &&
390            (receiver.IsJSPrimitive() || receiver == env->GetTaggedObjectFunctionPrototype()))) {
391            PropertyDetector::InvalidateNumberStringNotRegexpLikeDetector(env);
392        }
393    } else if (key == globalConst->GetHandledFlagsString().GetTaggedValue() &&
394        (receiver.IsJSRegExp() || receiver == env->GetTaggedRegExpPrototype())) {
395        if (!PropertyDetector::IsRegExpFlagsDetectorValid(env)) {
396            return;
397        }
398        PropertyDetector::InvalidateRegExpFlagsDetector(env);
399    }
400}
401
402// static
403bool ObjectOperator::IsDetectorName(const JSThread *thread, JSTaggedValue key)
404{
405    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
406    uintptr_t start = GlobalEnv::GetFirstDetectorSymbolAddr(*env);
407    uintptr_t end = GlobalEnv::GetLastDetectorSymbolAddr(*env);
408    uintptr_t addr = key.GetRawData();
409    if ((start <= addr) && (addr <= end)) {
410        return true;
411    }
412    if (key == thread->GlobalConstants()->GetHandledFlagsString().GetTaggedValue()) {
413        return true;
414    }
415    return false;
416}
417
418SharedFieldType ObjectOperator::GetSharedFieldType() const
419{
420    return JSObject::Cast(holder_->GetTaggedObject())->GetJSHClass()->IsDictionaryMode()
421                              ? attributes_.GetDictSharedFieldType()
422                              : attributes_.GetSharedFieldType();
423}
424
425void ObjectOperator::ToPropertyDescriptor(PropertyDescriptor &desc) const
426{
427    DISALLOW_GARBAGE_COLLECTION;
428    if (!IsFound()) {
429        return;
430    }
431
432    if (!IsAccessorDescriptor()) {
433        desc.SetWritable(IsWritable());
434        JSTaggedValue val = GetValue();
435        desc.SetValue(JSHandle<JSTaggedValue>(thread_, val));
436        desc.SetSharedFieldType(GetSharedFieldType());
437    } else {
438        auto result = GetValue();
439        bool isPropertyBox = result.IsPropertyBox();
440        if (isPropertyBox) {
441            result = PropertyBox::Cast(result.GetTaggedObject())->GetValue();
442        }
443        AccessorData *accessor = AccessorData::Cast(result.GetTaggedObject());
444
445        if (UNLIKELY(accessor->IsInternal())) {
446            desc.SetWritable(IsWritable());
447            auto val = accessor->CallInternalGet(thread_, JSHandle<JSObject>::Cast(GetHolder()));
448            JSMutableHandle<JSTaggedValue> value(thread_, val);
449            if (isPropertyBox) {
450                JSHandle<PropertyBox> cell(value_);
451                cell->SetValue(thread_, val);
452                value.Update(cell);
453            }
454            desc.SetValue(value);
455        } else {
456            desc.SetGetter(JSHandle<JSTaggedValue>(thread_, accessor->GetGetter()));
457            desc.SetSetter(JSHandle<JSTaggedValue>(thread_, accessor->GetSetter()));
458        }
459    }
460
461    desc.SetEnumerable(IsEnumerable());
462    desc.SetConfigurable(IsConfigurable());
463}
464
465void ObjectOperator::GlobalLookupProperty()
466{
467    GlobalLookupPropertyInHolder();
468    if (IsFound()) {
469        return;
470    }
471    JSTaggedValue proto = JSTaggedValue::GetPrototype(thread_, holder_);
472    RETURN_IF_ABRUPT_COMPLETION(thread_);
473    if (!proto.IsHeapObject()) {
474        return;
475    }
476    holder_.Update(proto);
477    if (holder_->IsJSProxy()) {
478        return;
479    }
480    SetIsOnPrototype(true);
481    LookupProperty();
482}
483
484void ObjectOperator::LookupProperty()
485{
486    while (true) {
487        if (holder_->IsJSProxy()) {
488            return;
489        }
490        UpdateIsTSHClass();
491        LookupPropertyInHolder();
492        if (IsFound()) {
493            return;
494        }
495
496        JSTaggedValue proto = JSTaggedValue::GetPrototype(thread_, holder_);
497        RETURN_IF_ABRUPT_COMPLETION(thread_);
498        if (!proto.IsHeapObject()) {
499            return;
500        }
501
502        holder_.Update(proto);
503        SetIsOnPrototype(true);
504    }
505}
506
507void ObjectOperator::LookupGlobal(const JSHandle<JSObject> &obj)
508{
509    ASSERT(obj->IsJSGlobalObject());
510    if (IsElement()) {
511        LookupElementInlinedProps(obj);
512        return;
513    }
514    TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
515    if (array->GetLength() == 0) {
516        return;
517    }
518    GlobalDictionary *dict = GlobalDictionary::Cast(array);
519    int entry = dict->FindEntry(key_.GetTaggedValue());
520    if (entry == -1) {
521        return;
522    }
523    JSTaggedValue value(dict->GetBox(entry));
524    auto attr = dict->GetAttributes(entry).GetValue();
525    SetFound(entry, value, attr, true);
526}
527
528void ObjectOperator::LookupPropertyInlinedProps(const JSHandle<JSObject> &obj)
529{
530    if (IsElement()) {
531        LookupElementInlinedProps(obj);
532        return;
533    }
534
535    if (!obj.GetTaggedValue().IsJSObject()) {
536        return;
537    }
538
539    if (obj->IsJSGlobalObject()) {
540        DISALLOW_GARBAGE_COLLECTION;
541        TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
542        if (array->GetLength() == 0) {
543            return;
544        }
545
546        GlobalDictionary *dict = GlobalDictionary::Cast(array);
547        int entry = dict->FindEntry(key_.GetTaggedValue());
548        if (entry == -1) {
549            return;
550        }
551
552        JSTaggedValue value(dict->GetBox(entry));
553        auto attr = dict->GetAttributes(entry).GetValue();
554        SetFound(entry, value, attr, !IsFoundDict());
555        return;
556    }
557
558    TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
559    if (!array->IsDictionaryMode()) {
560        JSHClass *jshclass = obj->GetJSHClass();
561        int entry = JSHClass::FindPropertyEntry(thread_, jshclass, key_.GetTaggedValue());
562        if (entry == -1) {
563            return;
564        }
565        JSTaggedValue attrs = jshclass->GetLayout();
566        LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetTaggedObject());
567        PropertyAttributes attr(layoutInfo->GetAttr(entry));
568        ASSERT(entry == static_cast<int>(attr.GetOffset()));
569        JSTaggedValue value;
570        if (attr.IsInlinedProps()) {
571            value = obj->GetPropertyInlinedPropsWithRep(entry, attr);
572            if (value.IsHole()) {
573                if (receiverHoleEntry_ == -1 && receiver_ == holder_) {
574                    receiverHoleEntry_ = entry;
575                }
576                return;
577            }
578        } else {
579            entry -= static_cast<int>(jshclass->GetInlinedProperties());
580            value = array->Get(entry);
581        }
582
583        SetFound(entry, value, attr.GetValue(), !IsFoundDict());
584        return;
585    }
586    SetFoundDict(true);
587    NameDictionary *dict = NameDictionary::Cast(array);
588    int entry = dict->FindEntry(key_.GetTaggedValue());
589    if (entry == -1) {
590        return;
591    }
592
593    JSTaggedValue value = dict->GetValue(entry);
594    auto attr = dict->GetAttributes(entry).GetValue();
595    SetFound(entry, value, attr, false);
596}
597
598void ObjectOperator::TransitionForAttributeChanged(const JSHandle<JSObject> &receiver, PropertyAttributes attr)
599{
600    if (IsElement()) {
601        uint32_t index = GetIndex();
602        if (!receiver->GetJSHClass()->IsDictionaryElement()) {
603            JSObject::ElementsToDictionary(thread_, receiver);
604            RETURN_IF_ABRUPT_COMPLETION(thread_);
605            auto dict = NumberDictionary::Cast(receiver->GetElements().GetTaggedObject());
606            index = static_cast<uint32_t>(dict->FindEntry(JSTaggedValue(index)));
607            PropertyAttributes origin = dict->GetAttributes(index);
608            attr.SetDictionaryOrder(origin.GetDictionaryOrder());
609            dict->SetAttributes(thread_, index, attr);
610        } else {
611            auto dict = NumberDictionary::Cast(receiver->GetElements().GetTaggedObject());
612            dict->SetAttributes(thread_, index, attr);
613        }
614        // update found result
615        UpdateFound(index, attr.GetValue(), false, true);
616    } else if (receiver->IsJSGlobalObject()) {
617        uint32_t index = GetIndex();
618        JSHandle<GlobalDictionary> dictHandle(thread_, receiver->GetProperties());
619        dictHandle->SetAttributes(thread_, index, attr);
620        GlobalDictionary::InvalidatePropertyBox(thread_, dictHandle, index);
621    } else {
622        uint32_t index = GetIndex();
623        if (!receiver->GetJSHClass()->IsDictionaryMode()) {
624            JSHandle<NameDictionary> dict(JSObject::TransitionToDictionary(thread_, receiver));
625            RETURN_IF_ABRUPT_COMPLETION(thread_);
626            index = static_cast<uint32_t>(dict->FindEntry(key_.GetTaggedValue()));
627            PropertyAttributes origin = dict->GetAttributes(index);
628            attr.SetDictSharedFieldType(attr.GetSharedFieldType());
629            attr.SetDictionaryOrder(origin.GetDictionaryOrder());
630            dict->SetAttributes(thread_, index, attr);
631        } else {
632            auto dict = NameDictionary::Cast(receiver->GetProperties().GetTaggedObject());
633            dict->SetAttributes(thread_, index, attr);
634        }
635        // update found result
636        UpdateFound(index, attr.GetValue(), false, true);
637    }
638}
639
640bool ObjectOperator::UpdateValueAndDetails(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
641                                           PropertyAttributes attr, bool attrChanged)
642{
643    auto valueAccessor = GetValue();
644    if (valueAccessor.IsPropertyBox()) {
645        valueAccessor = PropertyBox::Cast(valueAccessor.GetTaggedObject())->GetValue();
646    }
647    bool isInternalAccessor = IsAccessorDescriptor()
648        && AccessorData::Cast(valueAccessor.GetTaggedObject())->IsInternal();
649    if (!attrChanged) {
650        return UpdateDataValue(receiver, value, isInternalAccessor);
651    }
652    if (attr.IsWritable()) {
653        TransitionForAttributeChanged(receiver, attr);
654        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false);
655        return UpdateDataValue(receiver, value, isInternalAccessor);
656    }
657    bool res = UpdateDataValue(receiver, value, isInternalAccessor);
658    if (res) {
659        TransitionForAttributeChanged(receiver, attr);
660        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false);
661    }
662    return res;
663}
664
665bool ObjectOperator::UpdateDataValue(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
666                                     bool isInternalAccessor, bool mayThrow)
667{
668    if (IsElement()) {
669        TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
670        if (!elements->IsDictionaryMode()) {
671            if (receiver.GetTaggedValue().IsJSCOWArray()) {
672                JSArray::CheckAndCopyArray(thread_, JSHandle<JSArray>(receiver));
673            } else if (receiver->IsTypedArray()) {
674                JSTaggedValue holder = receiver.GetTaggedValue();
675                JSType jsType = holder.GetTaggedObject()->GetClass()->GetObjectType();
676                JSTaggedValue typedArrayProperty = JSTypedArray::FastSetPropertyByIndex(thread_,
677                    receiver.GetTaggedValue(), GetIndex(), value.GetTaggedValue(), jsType);
678                RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false);
679                if (typedArrayProperty.IsHole()) {
680                    return false;
681                }
682                return true;
683            }
684            ElementsKind oldKind = receiver->GetClass()->GetElementsKind();
685            if (JSHClass::TransitToElementsKind(thread_, receiver, value)) {
686                SetIsTransition(true);
687                ElementsKind newKind = receiver->GetClass()->GetElementsKind();
688                // newKind != currentKind, we need to convert the whole array to the newKind.
689                Elements::MigrateArrayWithKind(thread_, receiver, oldKind, newKind);
690            }
691            ElementAccessor::Set(thread_, receiver, GetIndex(), value, false);
692            return true;
693        }
694
695        NumberDictionary *dict = NumberDictionary::Cast(elements);
696        dict->UpdateValue(thread_, GetIndex(), value.GetTaggedValue());
697        return true;
698    }
699
700    if (receiver->IsJSGlobalObject()) {
701        // need update cell type ?
702        auto *dict = GlobalDictionary::Cast(receiver->GetProperties().GetTaggedObject());
703        if (isInternalAccessor && !value->IsAccessor()) {
704            PropertyAttributes attr = dict->GetAttributes(GetIndex());
705            attr.SetIsAccessor(false);
706            dict->SetAttributes(thread_, GetIndex(), attr);
707        }
708        PropertyBox *cell = dict->GetBox(GetIndex());
709        cell->SetValue(thread_, value.GetTaggedValue());
710        return true;
711    }
712
713    if (isInternalAccessor) {
714        auto accessor = AccessorData::Cast(GetValue().GetTaggedObject());
715        if (accessor->HasSetter()) {
716            bool res = accessor->CallInternalSet(thread_, JSHandle<JSObject>(receiver), value, mayThrow);
717            if (receiver->GetJSHClass()->IsDictionaryMode()) {
718                SetIsInlinedProps(false);
719                SetFastMode(false);
720            }
721            return res;
722        }
723    }
724
725    JSMutableHandle<TaggedArray> properties(thread_, TaggedArray::Cast(receiver->GetProperties().GetTaggedObject()));
726    if (!properties->IsDictionaryMode()) {
727        PropertyAttributes attr = GetAttr();
728        uint32_t offset = index_;
729        if (!attr.IsInlinedProps()) {
730            auto *hclass = receiver_->GetTaggedObject()->GetClass();
731            offset += hclass->GetInlinedProperties();
732        }
733        attr.SetOffset(offset);
734        JSHandle<JSObject> objHandle(receiver_);
735        ElementsKind oldKind = objHandle->GetJSHClass()->GetElementsKind();
736        auto actualValue =
737            JSHClass::ConvertOrTransitionWithRep(thread_, objHandle, key_, value, attr);
738        JSObject::TryMigrateToGenericKindForJSObject(thread_, objHandle, oldKind);
739        if (actualValue.isTransition) {
740            SetIsTransition(true);
741        }
742        attributes_.SetRepresentation(attr.GetRepresentation());
743
744        if (attr.IsInlinedProps()) {
745            receiver->SetPropertyInlinedPropsWithRep(thread_, GetIndex(), actualValue.value);
746        } else {
747            if (receiver.GetTaggedValue().IsJSCOWArray()) {
748                JSArray::CheckAndCopyArray(thread_, JSHandle<JSArray>(receiver));
749                properties.Update(JSHandle<JSArray>(receiver)->GetProperties());
750            }
751            if (actualValue.isTagged) {
752                properties->Set<true>(thread_, GetIndex(), value.GetTaggedValue());
753            } else {
754                properties->Set<false>(thread_, GetIndex(), actualValue.value);
755            }
756        }
757    } else {
758        properties.GetObject<NameDictionary>()->UpdateValue(thread_, GetIndex(), value.GetTaggedValue());
759    }
760    return true;
761}
762
763bool ObjectOperator::WriteDataProperty(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc)
764{
765    PropertyAttributes attr = GetAttr();
766    bool attrChanged = false;
767
768    // composed new attribute from desc
769    if (desc.HasConfigurable() && attr.IsConfigurable() != desc.IsConfigurable()) {
770        attr.SetConfigurable(desc.IsConfigurable());
771        attrChanged = true;
772    }
773    if (desc.HasEnumerable() && attr.IsEnumerable() != desc.IsEnumerable()) {
774        attr.SetEnumerable(desc.IsEnumerable());
775        attrChanged = true;
776    }
777
778    if (!desc.IsAccessorDescriptor()) {
779        if (desc.HasWritable() && attr.IsWritable() != desc.IsWritable()) {
780            attr.SetWritable(desc.IsWritable());
781            attrChanged = true;
782        }
783        if (!desc.HasValue()) {
784            if (attrChanged) {
785                TransitionForAttributeChanged(receiver, attr);
786                RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false);
787            }
788            return true;
789        }
790
791        if (IsAccessorDescriptor()) {
792            TaggedObject *obj = GetValue().GetTaggedObject();
793            if (receiver->IsJSGlobalObject()) {
794                JSTaggedValue val = GetValue();
795                if (val.IsPropertyBox()) {
796                    PropertyBox *cell = PropertyBox::Cast(val.GetTaggedObject());
797                    obj = cell->GetValue().GetTaggedObject();
798                }
799            }
800            auto accessor = AccessorData::Cast(obj);
801            if (!accessor->IsInternal() || !accessor->HasSetter()) {
802                attr.SetIsAccessor(false);
803                attrChanged = true;
804            }
805        }
806
807        return UpdateValueAndDetails(receiver, desc.GetValue(), attr, attrChanged);
808    } else {
809        if (IsAccessorDescriptor() && !IsElement()) {
810            TaggedArray *properties = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
811            if (attrChanged && !properties->IsDictionaryMode()) {
812                // as some accessorData is in globalEnv, we need to new accessorData.
813                JSHandle<AccessorData> accessor = thread_->GetEcmaVM()->GetFactory()->NewAccessorData();
814
815                if (desc.HasGetter()) {
816                    accessor->SetGetter(thread_, desc.GetGetter().GetTaggedValue());
817                } else {
818                    accessor->SetGetter(thread_, JSHandle<AccessorData>::Cast(value_)->GetGetter());
819                }
820                if (desc.HasSetter()) {
821                    accessor->SetSetter(thread_, desc.GetSetter().GetTaggedValue());
822                } else {
823                    accessor->SetSetter(thread_, JSHandle<AccessorData>::Cast(value_)->GetSetter());
824                }
825
826                JSHandle<NameDictionary> dict(JSObject::TransitionToDictionary(thread_, receiver));
827                RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false);
828                int entry = dict->FindEntry(key_.GetTaggedValue());
829                ASSERT(entry != -1);
830                dict->UpdateValueAndAttributes(thread_, entry, accessor.GetTaggedValue(), attr);
831                return true;
832            }
833        }
834
835        auto valueAccessor = GetValue();
836        if (valueAccessor.IsPropertyBox()) {
837            valueAccessor = PropertyBox::Cast(valueAccessor.GetTaggedObject())->GetValue();
838        }
839        JSHandle<AccessorData> accessor =
840            (IsAccessorDescriptor() && !JSHandle<AccessorData>(thread_, valueAccessor)->IsInternal()) ?
841            JSHandle<AccessorData>(thread_, valueAccessor) :
842            thread_->GetEcmaVM()->GetFactory()->NewAccessorData();
843        if (desc.HasGetter()) {
844            accessor->SetGetter(thread_, desc.GetGetter().GetTaggedValue());
845        }
846
847        if (desc.HasSetter()) {
848            accessor->SetSetter(thread_, desc.GetSetter().GetTaggedValue());
849        }
850
851        if (!IsAccessorDescriptor()) {
852            attr.SetIsAccessor(true);
853            attrChanged = true;
854        }
855
856        JSHandle<JSTaggedValue> value = JSHandle<JSTaggedValue>::Cast(accessor);
857        bool success = UpdateValueAndDetails(receiver, value, attr, attrChanged);
858        if (success) {
859            JSHandle<JSObject> obj(receiver);
860            if (obj->GetJSHClass()->IsPrototype()) {
861                JSHandle<ProtoChangeMarker> markerHandle = thread_->GetEcmaVM()->GetFactory()->NewProtoChangeMarker();
862                obj->GetJSHClass()->SetProtoChangeMarker(thread_, markerHandle.GetTaggedValue());
863            }
864            JSHClass::NotifyAccessorChanged(thread_, JSHandle<JSHClass>(thread_, obj->GetJSHClass()));
865        }
866        return success;
867    }
868}
869
870void ObjectOperator::DeletePropertyInHolder()
871{
872    if (IsElement()) {
873        return DeleteElementInHolder();
874    }
875    ObjectOperator::UpdateDetector(thread_, holder_.GetTaggedValue(), key_.GetTaggedValue());
876    JSObject::DeletePropertyInternal(thread_, JSHandle<JSObject>(holder_), key_, GetIndex());
877}
878
879bool ObjectOperator::AddProperty(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
880                                 PropertyAttributes attr)
881{
882    if (IsElement()) {
883        ElementsKind oldKind = receiver->GetClass()->GetElementsKind();
884        uint32_t oldLen = receiver.GetTaggedValue().IsJSArray() ?
885            JSArray::Cast(*receiver)->GetArrayLength() : 0;
886        bool ret = JSObject::AddElementInternal(thread_, receiver, elementIndex_, value, attr);
887        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread_, false);
888        ElementsKind newKind = receiver->GetClass()->GetElementsKind();
889        uint32_t newLen = receiver.GetTaggedValue().IsJSArray() ?
890            JSArray::Cast(*receiver)->GetArrayLength() : 0;
891        SetElementOutOfBounds(newLen > oldLen);
892        bool isTransited = false;
893        if (receiver.GetTaggedValue().IsJSArray() && (newKind != oldKind)) {
894            isTransited = true;
895        }
896        bool isDict = receiver->GetJSHClass()->IsDictionaryElement();
897        SetFound(elementIndex_, value.GetTaggedValue(), attr.GetValue(), !isDict, isTransited);
898        return ret;
899    }
900
901    ResetStateForAddProperty();
902    receiver_.Update(receiver.GetTaggedValue());
903    SetAttr(attr.GetValue());
904    AddPropertyInternal(value);
905    return true;
906}
907
908void ObjectOperator::WriteElement(const JSHandle<JSObject> &receiver, JSHandle<JSTaggedValue> value) const
909{
910    ASSERT(IsElement() && GetIndex() < JSObject::MAX_ELEMENT_INDEX);
911
912    if (!ElementAccessor::IsDictionaryMode(receiver)) {
913        ElementAccessor::Set(thread_, receiver, index_, value, true);
914        return;
915    }
916
917    TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
918    NumberDictionary *dictionary = NumberDictionary::Cast(elements);
919    dictionary->UpdateValue(thread_, GetIndex(), value.GetTaggedValue());
920}
921
922void ObjectOperator::DeleteElementInHolder() const
923{
924    JSHandle<JSObject> obj(holder_);
925    if (obj->IsJSSArray()) {
926        auto arrayHandler = JSHandle<JSSharedArray>::Cast(obj);
927        JSSharedArray::DeleteInElementMode(thread_, arrayHandler);
928        return;
929    }
930    JSHandle<JSTaggedValue> holeHandle(thread_, JSTaggedValue::Hole());
931    if (!ElementAccessor::IsDictionaryMode(obj)) {
932        ElementAccessor::Set(thread_, obj, index_, holeHandle, true, ElementsKind::HOLE);
933        JSObject::ElementsToDictionary(thread_, JSHandle<JSObject>(holder_));
934        RETURN_IF_ABRUPT_COMPLETION(thread_);
935    } else {
936        TaggedArray *elements = TaggedArray::Cast(obj->GetElements().GetTaggedObject());
937        JSHandle<NumberDictionary> dictHandle(thread_, elements);
938        JSHandle<NumberDictionary> newDict = NumberDictionary::Remove(thread_, dictHandle, GetIndex());
939        obj->SetElements(thread_, newDict);
940    }
941}
942
943void ObjectOperator::SetFound(uint32_t index, JSTaggedValue value, uint64_t attr, bool mode, bool transition)
944{
945    SetIndex(index);
946    SetValue(value);
947    SetFastMode(mode);
948    SetIsTransition(transition);
949    SetAttr(attr);
950}
951
952void ObjectOperator::UpdateFound(uint32_t index, uint64_t attr, bool mode, bool transition)
953{
954    SetIndex(index);
955    SetFastMode(mode);
956    SetIsTransition(transition);
957    SetAttr(attr);
958}
959
960void ObjectOperator::ResetState()
961{
962    // index may used by element
963    SetIndex(NOT_FOUND_INDEX);
964    SetValue(JSTaggedValue::Undefined());
965    SetFastMode(false);
966    SetAttr(0);
967    SetIsOnPrototype(false);
968    SetHasReceiver(false);
969    SetIsTSHClass(false);
970}
971
972void ObjectOperator::ResetStateForAddProperty()
973{
974    bool isOnPrototype = IsOnPrototype();
975    ResetState();
976    SetIsOnPrototype(isOnPrototype);
977}
978
979void ObjectOperator::LookupElementInlinedProps(const JSHandle<JSObject> &obj)
980{
981    // if is js string, do special.
982    if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(obj.GetTaggedValue().GetTaggedObject())->IsString()) {
983        PropertyDescriptor desc(thread_);
984        bool status = JSPrimitiveRef::StringGetIndexProperty(thread_, obj, elementIndex_, &desc);
985        if (status) {
986            PropertyAttributes attr(desc);
987            SetFound(elementIndex_, desc.GetValue().GetTaggedValue(), attr.GetValue(), !IsFoundDict());
988            return;
989        }
990    }
991    {
992        DISALLOW_GARBAGE_COLLECTION;
993        if (obj->IsTypedArray()) {
994            JSTaggedValue val = JSTypedArray::FastElementGet(thread_,
995                JSHandle<JSTaggedValue>::Cast(obj), elementIndex_).GetValue().GetTaggedValue();
996            RETURN_IF_ABRUPT_COMPLETION(thread_);
997            if (!val.IsHole()) {
998                SetFound(elementIndex_, val, PropertyAttributes::GetDefaultAttributes(), !IsFoundDict());
999            }
1000            return;
1001        }
1002        TaggedArray *elements = TaggedArray::Cast(obj->GetElements().GetTaggedObject());
1003        if (elements->GetLength() == 0) {
1004            return;  // Empty Array
1005        }
1006
1007        if (!elements->IsDictionaryMode()) {
1008            if (elements->GetLength() <= elementIndex_) {
1009                return;
1010            }
1011
1012            JSTaggedValue value = ElementAccessor::Get(obj, elementIndex_);
1013            if (value.IsHole()) {
1014                return;
1015            }
1016            SetFound(elementIndex_, value, PropertyAttributes::GetDefaultAttributes(), !IsFoundDict());
1017        } else {
1018            SetFoundDict(true);
1019            NumberDictionary *dictionary = NumberDictionary::Cast(obj->GetElements().GetTaggedObject());
1020            JSTaggedValue key(static_cast<int>(elementIndex_));
1021            int entry = dictionary->FindEntry(key);
1022            if (entry == -1) {
1023                return;
1024            }
1025
1026            auto attr = dictionary->GetAttributes(entry).GetValue();
1027            SetFound(entry, dictionary->GetValue(entry), attr, false);
1028        }
1029    }
1030}
1031
1032void ObjectOperator::AddPropertyInternal(const JSHandle<JSTaggedValue> &value)
1033{
1034    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();
1035    JSHandle<JSObject> obj(GetReceiver());
1036    PropertyAttributes attr = GetAttr();
1037    if (obj->IsJSGlobalObject()) {
1038        JSMutableHandle<GlobalDictionary> dict(thread_, obj->GetProperties());
1039        if (dict->GetLength() == 0) {
1040            dict.Update(GlobalDictionary::Create(thread_));
1041        }
1042
1043        // Add PropertyBox to global dictionary
1044        JSHandle<PropertyBox> cellHandle = factory->NewPropertyBox(key_);
1045        cellHandle->SetValue(thread_, value.GetTaggedValue());
1046        PropertyBoxType cellType = value->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT;
1047        attr.SetBoxType(cellType);
1048
1049        JSHandle<GlobalDictionary> properties =
1050            GlobalDictionary::PutIfAbsent(thread_, dict, key_, JSHandle<JSTaggedValue>(cellHandle), attr);
1051        obj->SetProperties(thread_, properties);
1052        // index and fastMode is not essential for global obj;
1053        SetFound(0, cellHandle.GetTaggedValue(), attr.GetValue(), true);
1054        return;
1055    }
1056
1057    // The property has already existed whose value is hole, initialized by speculative hclass.
1058    // Not need AddProperty,just SetProperty
1059    if (receiverHoleEntry_ != -1) {
1060        attr.SetOffset(receiverHoleEntry_);
1061        JSHandle<JSObject> objHandle(receiver_);
1062        ElementsKind oldKind = objHandle->GetJSHClass()->GetElementsKind();
1063        auto actualValue =
1064            JSHClass::ConvertOrTransitionWithRep(thread_, objHandle, key_, value, attr);
1065        JSObject::TryMigrateToGenericKindForJSObject(thread_, objHandle, oldKind);
1066        if (actualValue.isTransition) {
1067            SetIsTransition(true);
1068        }
1069        attributes_.SetRepresentation(attr.GetRepresentation());
1070        auto *hclass = receiver_->GetTaggedObject()->GetClass();
1071        if (actualValue.isTagged) {
1072            JSObject::Cast(receiver_.GetTaggedValue())->SetProperty<true>(thread_, hclass,
1073                                                                          attr, value.GetTaggedValue());
1074        } else {
1075            JSObject::Cast(receiver_.GetTaggedValue())->SetProperty<false>(thread_, hclass, attr, actualValue.value);
1076        }
1077        uint32_t index = attr.IsInlinedProps() ? attr.GetOffset() :
1078                attr.GetOffset() - obj->GetJSHClass()->GetInlinedProperties();
1079        SetIsTSHClass(true);
1080        SetIsOnPrototype(false);
1081        SetFound(index, value.GetTaggedValue(), attr.GetValue(), true);
1082        return;
1083    }
1084
1085    attr = ObjectFastOperator::AddPropertyByName(thread_, obj, key_, value, attr);
1086    RETURN_IF_ABRUPT_COMPLETION(thread_);
1087    if (obj->GetJSHClass()->IsDictionaryMode()) {
1088        SetFound(0, value.GetTaggedValue(), attr.GetValue(), false);
1089    } else {
1090        uint32_t index = attr.IsInlinedProps() ? attr.GetOffset() :
1091                attr.GetOffset() - obj->GetJSHClass()->GetInlinedProperties();
1092        SetFound(index, value.GetTaggedValue(), attr.GetValue(), true, true);
1093    }
1094}
1095
1096void ObjectOperator::DefineSetter(const JSHandle<JSTaggedValue> &value)
1097{
1098    ASSERT(IsAccessorDescriptor());
1099    JSHandle<AccessorData> accessor = JSHandle<AccessorData>::Cast(value_);
1100    accessor->SetSetter(thread_, value.GetTaggedValue());
1101    UpdateDataValue(JSHandle<JSObject>::Cast(receiver_), JSHandle<JSTaggedValue>::Cast(accessor), false);
1102}
1103
1104void ObjectOperator::DefineGetter(const JSHandle<JSTaggedValue> &value)
1105{
1106    ASSERT(IsAccessorDescriptor());
1107    JSHandle<AccessorData> accessor = JSHandle<AccessorData>::Cast(value_);
1108    accessor->SetGetter(thread_, value.GetTaggedValue());
1109    UpdateDataValue(JSHandle<JSObject>::Cast(receiver_), JSHandle<JSTaggedValue>::Cast(accessor), false);
1110}
1111}  // namespace panda::ecmascript
1112