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