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