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