• 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 "object_operator.h"
17 #include "ecma_vm.h"
18 #include "ecmascript/accessor_data.h"
19 #include "ecmascript/global_dictionary-inl.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/ic/property_box.h"
22 #include "ecmascript/interpreter/fast_runtime_stub-inl.h"
23 #include "ecmascript/js_array.h"
24 #include "ecmascript/js_function.h"
25 #include "ecmascript/js_hclass-inl.h"
26 #include "ecmascript/js_object-inl.h"
27 #include "ecmascript/js_primitive_ref.h"
28 #include "ecmascript/mem/c_string.h"
29 #include "ecmascript/object_factory.h"
30 #include "ecmascript/tagged_dictionary.h"
31 #include "global_dictionary.h"
32 
33 namespace panda::ecmascript {
HandleKey(const JSHandle<JSTaggedValue> & key)34 void ObjectOperator::HandleKey(const JSHandle<JSTaggedValue> &key)
35 {
36     if (key->IsInt()) {
37         int32_t keyInt = key->GetInt();
38         if (keyInt >= 0) {
39             elementIndex_ = static_cast<uint32_t>(keyInt);
40             return;
41         }
42         key_ = JSHandle<JSTaggedValue>::Cast(base::NumberHelper::NumberToString(thread_, JSTaggedValue(keyInt)));
43         return;
44     }
45 
46     if (key->IsString()) {
47         uint32_t index = 0;
48         if (JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index)) {
49             ASSERT(index < JSObject::MAX_ELEMENT_INDEX);
50             elementIndex_ = index;
51             return;
52         }
53         if (EcmaString::Cast(key->GetTaggedObject())->IsInternString()) {
54             key_ = key;
55             return;
56         }
57         key_ = JSHandle<JSTaggedValue>(thread_, thread_->GetEcmaVM()->GetFactory()->InternString(key));
58         return;
59     }
60 
61     if (key->IsDouble()) {
62         double number = key->GetDouble();
63         if (number >= 0 && number < JSObject::MAX_ELEMENT_INDEX) {
64             auto integer = static_cast<uint32_t>(number);
65             if (integer == number) {
66                 elementIndex_ = static_cast<uint32_t>(number);
67                 return;
68             }
69         }
70         key_ = JSHandle<JSTaggedValue>::Cast(base::NumberHelper::NumberToString(thread_, key.GetTaggedValue()));
71         return;
72     }
73 
74     if (key->IsSymbol()) {
75         key_ = key;
76         return;
77     }
78 
79     JSHandle<JSTaggedValue> keyHandle(thread_, JSTaggedValue::ToPrimitive(thread_, key, PREFER_STRING));
80     if (key->IsSymbol()) {
81         key_ = keyHandle;
82         return;
83     }
84     key_ = JSHandle<JSTaggedValue>(thread_,
85                                    thread_->GetEcmaVM()->GetFactory()->InternString(
86                                        JSHandle<JSTaggedValue>::Cast(JSTaggedValue::ToString(thread_, keyHandle))));
87 }
88 
UpdateHolder()89 void ObjectOperator::UpdateHolder()
90 {
91     if (holder_->IsString() &&
92         (IsElement() && elementIndex_ < EcmaString::Cast(holder_->GetTaggedObject())->GetLength())) {
93         holder_.Update(JSPrimitiveRef::StringCreate(thread_, holder_).GetTaggedValue());
94     } else {
95         holder_.Update(JSTaggedValue::ToPrototypeOrObj(thread_, holder_).GetTaggedValue());
96     }
97 }
98 
StartLookUp(OperatorType type)99 void ObjectOperator::StartLookUp(OperatorType type)
100 {
101     UpdateHolder();
102 
103     if (type == OperatorType::OWN) {
104         LookupPropertyInHolder();
105     } else {
106         LookupProperty();
107     }
108 }
109 
StartGlobalLookUp(OperatorType type)110 void ObjectOperator::StartGlobalLookUp(OperatorType type)
111 {
112     UpdateHolder();
113 
114     if (type == OperatorType::OWN) {
115         GlobalLookupPropertyInHolder();
116     } else {
117         GlobalLookupProperty();
118     }
119 }
120 
ObjectOperator(JSThread * thread,const JSHandle<JSTaggedValue> & key,OperatorType type)121 ObjectOperator::ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &key, OperatorType type)
122     : thread_(thread),
123       holder_(thread, thread->GetEcmaVM()->GetGlobalEnv()->GetGlobalObject()),
124       receiver_(thread, thread->GetEcmaVM()->GetGlobalEnv()->GetGlobalObject())
125 {
126     HandleKey(key);
127     StartGlobalLookUp(type);
128 }
129 
ObjectOperator(JSThread * thread,const JSHandle<JSObject> & holder,const JSHandle<JSTaggedValue> & key,OperatorType type)130 ObjectOperator::ObjectOperator(JSThread *thread, const JSHandle<JSObject> &holder, const JSHandle<JSTaggedValue> &key,
131                                OperatorType type)
132     : thread_(thread), holder_(thread, holder.GetTaggedValue()), receiver_(thread, holder.GetTaggedValue())
133 {
134     HandleKey(key);
135     StartLookUp(type);
136 }
137 
ObjectOperator(JSThread * thread,const JSHandle<JSTaggedValue> & holder,const JSHandle<JSTaggedValue> & key,OperatorType type)138 ObjectOperator::ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder,
139                                const JSHandle<JSTaggedValue> &key, OperatorType type)
140     : thread_(thread), holder_(thread, holder.GetTaggedValue()), receiver_(thread, holder.GetTaggedValue())
141 {
142     HandleKey(key);
143     StartLookUp(type);
144 }
145 
ObjectOperator(JSThread * thread,const JSHandle<JSTaggedValue> & holder,uint32_t index,OperatorType type)146 ObjectOperator::ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder, uint32_t index,
147                                OperatorType type)
148     : thread_(thread),
149       holder_(thread, holder.GetTaggedValue()),
150       receiver_(thread, holder.GetTaggedValue()),
151       elementIndex_(index)
152 {
153     StartLookUp(type);
154 }
155 
ObjectOperator(JSThread * thread,const JSHandle<JSTaggedValue> & holder,const JSHandle<JSTaggedValue> & receiver,const JSHandle<JSTaggedValue> & key,OperatorType type)156 ObjectOperator::ObjectOperator(JSThread *thread, const JSHandle<JSTaggedValue> &holder,
157                                const JSHandle<JSTaggedValue> &receiver, const JSHandle<JSTaggedValue> &key,
158                                OperatorType type)
159     : thread_(thread), holder_(thread, holder.GetTaggedValue()), receiver_(thread, receiver.GetTaggedValue())
160 {
161     SetHasReceiver(true);
162     HandleKey(key);
163     StartLookUp(type);
164 }
165 
166 // op for fast path
ObjectOperator(JSThread * thread,const JSTaggedValue & receiver,const JSTaggedValue & name,OperatorType type)167 ObjectOperator::ObjectOperator(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name,
168                                OperatorType type)
169     : thread_(thread), holder_(thread, receiver), receiver_(thread, receiver), key_(thread, name)
170 {
171     ASSERT(name.IsStringOrSymbol());
172     StartLookUp(type);
173 }
FastGetValue()174 JSHandle<JSTaggedValue> ObjectOperator::FastGetValue()
175 {
176     ASSERT(IsFound() && !value_.IsEmpty());
177     if (value_->IsPropertyBox()) {
178         value_.Update(PropertyBox::Cast(value_->GetTaggedObject())->GetValue());
179     }
180     if (!IsAccessorDescriptor()) {
181         return value_;
182     }
183     AccessorData *accessor = AccessorData::Cast(value_->GetTaggedObject());
184     ASSERT(!accessor->IsInternal());
185     // 8. Return Call(getter, Receiver).
186     return JSHandle<JSTaggedValue>(thread_, JSObject::CallGetter(thread_, accessor, receiver_));
187 }
ObjectOperator(JSThread * thread,const JSTaggedValue & receiver,const JSTaggedValue & name,const PropertyAttributes & attr)188 ObjectOperator::ObjectOperator(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name,
189                                const PropertyAttributes &attr)
190     : thread_(thread), receiver_(thread, receiver), key_(thread, name)
191 {
192     SetAttr(attr);
193 }
FastAdd(JSThread * thread,const JSTaggedValue & receiver,const JSTaggedValue & name,const JSHandle<JSTaggedValue> & value,const PropertyAttributes & attr)194 void ObjectOperator::FastAdd(JSThread *thread, const JSTaggedValue &receiver, const JSTaggedValue &name,
195                              const JSHandle<JSTaggedValue> &value, const PropertyAttributes &attr)
196 {
197     ObjectOperator op(thread, receiver, name, attr);
198     op.AddPropertyInternal(value);
199 }
200 
ToPropertyDescriptor(PropertyDescriptor & desc) const201 void ObjectOperator::ToPropertyDescriptor(PropertyDescriptor &desc) const
202 {
203     DISALLOW_GARBAGE_COLLECTION;
204     if (!IsFound()) {
205         return;
206     }
207 
208     if (!IsAccessorDescriptor()) {
209         desc.SetWritable(IsWritable());
210         JSTaggedValue val = GetValue();
211         desc.SetValue(JSHandle<JSTaggedValue>(thread_, val));
212     } else {
213         AccessorData *accessor = AccessorData::Cast(GetValue().GetTaggedObject());
214 
215         if (UNLIKELY(accessor->IsInternal())) {
216             desc.SetWritable(IsWritable());
217             auto val = accessor->CallInternalGet(thread_, JSHandle<JSObject>::Cast(GetHolder()));
218             desc.SetValue(JSHandle<JSTaggedValue>(thread_, val));
219         } else {
220             desc.SetGetter(JSHandle<JSTaggedValue>(thread_, accessor->GetGetter()));
221             desc.SetSetter(JSHandle<JSTaggedValue>(thread_, accessor->GetSetter()));
222         }
223     }
224 
225     desc.SetEnumerable(IsEnumerable());
226     desc.SetConfigurable(IsConfigurable());
227 }
228 
GlobalLookupProperty()229 void ObjectOperator::GlobalLookupProperty()
230 {
231     GlobalLookupPropertyInHolder();
232     if (IsFound()) {
233         return;
234     }
235     JSTaggedValue proto = JSObject::Cast(holder_->GetTaggedObject())->GetPrototype(thread_);
236     if (!proto.IsHeapObject()) {
237         return;
238     }
239     holder_.Update(proto);
240     if (holder_->IsJSProxy()) {
241         return;
242     }
243     SetIsOnPrototype(true);
244     LookupProperty();
245 }
246 
LookupProperty()247 void ObjectOperator::LookupProperty()
248 {
249     while (true) {
250         LookupPropertyInHolder();
251         if (IsFound()) {
252             return;
253         }
254 
255         JSTaggedValue proto = holder_.GetObject<JSObject>()->GetPrototype(thread_);
256         if (!proto.IsHeapObject()) {
257             return;
258         }
259 
260         holder_.Update(proto);
261         if (holder_->IsJSProxy()) {
262             return;
263         }
264 
265         SetIsOnPrototype(true);
266     }
267 }
268 
LookupGlobal(const JSHandle<JSObject> & obj)269 void ObjectOperator::LookupGlobal(const JSHandle<JSObject> &obj)
270 {
271     ASSERT(obj->IsJSGlobalObject());
272     if (IsElement()) {
273         LookupElementInlinedProps(obj);
274         return;
275     }
276     TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
277     if (array->GetLength() == 0) {
278         return;
279     }
280     GlobalDictionary *dict = GlobalDictionary::Cast(array);
281     int entry = dict->FindEntry(key_.GetTaggedValue());
282     if (entry == -1) {
283         return;
284     }
285     JSTaggedValue value(dict->GetBox(entry));
286     uint32_t attr = dict->GetAttributes(entry).GetValue();
287     SetFound(entry, value, attr, true);
288 }
289 
LookupPropertyInlinedProps(const JSHandle<JSObject> & obj)290 void ObjectOperator::LookupPropertyInlinedProps(const JSHandle<JSObject> &obj)
291 {
292     if (IsElement()) {
293         LookupElementInlinedProps(obj);
294         return;
295     }
296 
297     if (obj->IsJSGlobalObject()) {
298         DISALLOW_GARBAGE_COLLECTION;
299         TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
300         if (array->GetLength() == 0) {
301             return;
302         }
303 
304         GlobalDictionary *dict = GlobalDictionary::Cast(array);
305         int entry = dict->FindEntry(key_.GetTaggedValue());
306         if (entry == -1) {
307             return;
308         }
309 
310         JSTaggedValue value(dict->GetBox(entry));
311         uint32_t attr = dict->GetAttributes(entry).GetValue();
312         SetFound(entry, value, attr, true);
313         return;
314     }
315 
316     TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
317     if (!array->IsDictionaryMode()) {
318         JSHClass *jshclass = obj->GetJSHClass();
319         JSTaggedValue attrs = jshclass->GetLayout();
320         LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetTaggedObject());
321         int propsNumber = jshclass->NumberOfProps();
322         int entry = layoutInfo->FindElementWithCache(thread_, jshclass, key_.GetTaggedValue(), propsNumber);
323         if (entry == -1) {
324             return;
325         }
326         PropertyAttributes attr(layoutInfo->GetAttr(entry));
327         ASSERT(entry == static_cast<int>(attr.GetOffset()));
328         JSTaggedValue value;
329         if (attr.IsInlinedProps()) {
330             value = obj->GetPropertyInlinedProps(entry);
331         } else {
332             entry -= jshclass->GetInlinedProperties();
333             value = array->Get(entry);
334         }
335 
336         SetFound(entry, value, attr.GetValue(), true);
337         return;
338     }
339 
340     NameDictionary *dict = NameDictionary::Cast(array);
341     int entry = dict->FindEntry(key_.GetTaggedValue());
342     if (entry == -1) {
343         return;
344     }
345 
346     JSTaggedValue value = dict->GetValue(entry);
347     uint32_t attr = dict->GetAttributes(entry).GetValue();
348     SetFound(entry, value, attr, false);
349 }
350 
TransitionForAttributeChanged(const JSHandle<JSObject> & receiver,PropertyAttributes attr)351 void ObjectOperator::TransitionForAttributeChanged(const JSHandle<JSObject> &receiver, PropertyAttributes attr)
352 {
353     if (IsElement()) {
354         uint32_t index = GetIndex();
355         if (!receiver->GetJSHClass()->IsDictionaryElement()) {
356             JSObject::ElementsToDictionary(thread_, receiver);
357             auto dict = NumberDictionary::Cast(receiver->GetElements().GetTaggedObject());
358             index = dict->FindEntry(JSTaggedValue(index));
359             PropertyAttributes origin = dict->GetAttributes(index);
360             attr.SetDictionaryOrder(origin.GetDictionaryOrder());
361             dict->SetAttributes(thread_, index, attr);
362         } else {
363             auto dict = NumberDictionary::Cast(receiver->GetElements().GetTaggedObject());
364             dict->SetAttributes(thread_, index, attr);
365         }
366         // update found result
367         UpdateFound(index, attr.GetValue(), false, true);
368     } else if (receiver->IsJSGlobalObject()) {
369         JSHandle<GlobalDictionary> dictHandle(thread_, receiver->GetProperties());
370         GlobalDictionary::InvalidatePropertyBox(thread_, dictHandle, GetIndex(), attr);
371     } else {
372         uint32_t index = GetIndex();
373         if (!receiver->GetJSHClass()->IsDictionaryMode()) {
374             JSHandle<NameDictionary> dict(JSObject::TransitionToDictionary(thread_, receiver));
375             index = dict->FindEntry(key_.GetTaggedValue());
376             PropertyAttributes origin = dict->GetAttributes(index);
377             attr.SetDictionaryOrder(origin.GetDictionaryOrder());
378             dict->SetAttributes(thread_, index, attr);
379         } else {
380             auto dict = NameDictionary::Cast(receiver->GetProperties().GetTaggedObject());
381             dict->SetAttributes(thread_, index, attr);
382         }
383         // update found result
384         UpdateFound(index, attr.GetValue(), false, true);
385     }
386 }
387 
UpdateValueAndDetails(const JSHandle<JSObject> & receiver,const JSHandle<JSTaggedValue> & value,PropertyAttributes attr,bool attrChanged)388 bool ObjectOperator::UpdateValueAndDetails(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
389                                            PropertyAttributes attr, bool attrChanged)
390 {
391     bool isInternalAccessor = IsAccessorDescriptor() && AccessorData::Cast(GetValue().GetHeapObject())->IsInternal();
392     if (attrChanged) {
393         TransitionForAttributeChanged(receiver, attr);
394     }
395     return UpdateDataValue(receiver, value, isInternalAccessor);
396 }
397 
UpdateDataValue(const JSHandle<JSObject> & receiver,const JSHandle<JSTaggedValue> & value,bool isInternalAccessor,bool mayThrow)398 bool ObjectOperator::UpdateDataValue(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
399                                      bool isInternalAccessor, bool mayThrow)
400 {
401     if (IsElement()) {
402         TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
403         if (!elements->IsDictionaryMode()) {
404             elements->Set(thread_, GetIndex(), value.GetTaggedValue());
405             return true;
406         }
407 
408         NumberDictionary *dict = NumberDictionary::Cast(elements);
409         dict->UpdateValue(thread_, GetIndex(), value.GetTaggedValue());
410         return true;
411     }
412 
413     if (receiver->IsJSGlobalObject()) {
414         // need update cell type ?
415         auto *dict = GlobalDictionary::Cast(receiver->GetProperties().GetTaggedObject());
416         PropertyBox *cell = dict->GetBox(GetIndex());
417         cell->SetValue(thread_, value.GetTaggedValue());
418         return true;
419     }
420 
421     if (isInternalAccessor) {
422         auto accessor = AccessorData::Cast(GetValue().GetHeapObject());
423         if (accessor->HasSetter()) {
424             return accessor->CallInternalSet(thread_, JSHandle<JSObject>(receiver), value, mayThrow);
425         }
426     }
427 
428     TaggedArray *properties = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
429     if (!properties->IsDictionaryMode()) {
430         PropertyAttributes attr = GetAttr();
431         if (attr.IsInlinedProps()) {
432             receiver->SetPropertyInlinedProps(thread_, GetIndex(), value.GetTaggedValue());
433         } else {
434             properties->Set(thread_, GetIndex(), value.GetTaggedValue());
435         }
436     } else {
437         NameDictionary::Cast(properties)->UpdateValue(thread_, GetIndex(), value.GetTaggedValue());
438     }
439     return true;
440 }
441 
WriteDataProperty(const JSHandle<JSObject> & receiver,const PropertyDescriptor & desc)442 bool ObjectOperator::WriteDataProperty(const JSHandle<JSObject> &receiver, const PropertyDescriptor &desc)
443 {
444     PropertyAttributes attr = GetAttr();
445     bool attrChanged = false;
446 
447     // composed new attribute from desc
448     if (desc.HasConfigurable() && attr.IsConfigurable() != desc.IsConfigurable()) {
449         attr.SetConfigurable(desc.IsConfigurable());
450         attrChanged = true;
451     }
452     if (desc.HasEnumerable() && attr.IsEnumerable() != desc.IsEnumerable()) {
453         attr.SetEnumerable(desc.IsEnumerable());
454         attrChanged = true;
455     }
456 
457     if (!desc.IsAccessorDescriptor()) {
458         if (desc.HasWritable() && attr.IsWritable() != desc.IsWritable()) {
459             attr.SetWritable(desc.IsWritable());
460             attrChanged = true;
461         }
462         if (!desc.HasValue()) {
463             if (attrChanged) {
464                 TransitionForAttributeChanged(receiver, attr);
465             }
466             return true;
467         }
468 
469         if (IsAccessorDescriptor()) {
470             auto accessor = AccessorData::Cast(GetValue().GetHeapObject());
471             if (!accessor->IsInternal() || !accessor->HasSetter()) {
472                 attr.SetIsAccessor(false);
473                 attrChanged = true;
474             }
475         }
476 
477         return UpdateValueAndDetails(receiver, desc.GetValue(), attr, attrChanged);
478     } else {
479         if (IsAccessorDescriptor() && !IsElement()) {
480             TaggedArray *properties = TaggedArray::Cast(receiver->GetProperties().GetTaggedObject());
481             if (!properties->IsDictionaryMode()) {
482                 // as some accessorData is in globalEnv, we need to new accessorData.
483                 JSHandle<AccessorData> accessor = thread_->GetEcmaVM()->GetFactory()->NewAccessorData();
484 
485                 if (desc.HasGetter()) {
486                     accessor->SetGetter(thread_, desc.GetGetter().GetTaggedValue());
487                 } else {
488                     accessor->SetGetter(thread_, JSHandle<AccessorData>::Cast(value_)->GetGetter());
489                 }
490                 if (desc.HasSetter()) {
491                     accessor->SetSetter(thread_, desc.GetSetter().GetTaggedValue());
492                 } else {
493                     accessor->SetSetter(thread_, JSHandle<AccessorData>::Cast(value_)->GetSetter());
494                 }
495 
496                 JSHandle<NameDictionary> dict(JSObject::TransitionToDictionary(thread_, receiver));
497                 int entry = dict->FindEntry(key_.GetTaggedValue());
498                 ASSERT(entry != -1);
499                 dict->UpdateValueAndAttributes(thread_, entry, accessor.GetTaggedValue(), attr);
500                 return true;
501             }
502         }
503 
504         JSHandle<AccessorData> accessor = IsAccessorDescriptor()
505                                               ? JSHandle<AccessorData>::Cast(value_)
506                                               : thread_->GetEcmaVM()->GetFactory()->NewAccessorData();
507         if (desc.HasGetter()) {
508             accessor->SetGetter(thread_, desc.GetGetter().GetTaggedValue());
509         }
510 
511         if (desc.HasSetter()) {
512             accessor->SetSetter(thread_, desc.GetSetter().GetTaggedValue());
513         }
514 
515         if (!IsAccessorDescriptor()) {
516             attr.SetIsAccessor(true);
517             attrChanged = true;
518         }
519 
520         JSHandle<JSTaggedValue> value = JSHandle<JSTaggedValue>::Cast(accessor);
521         return UpdateValueAndDetails(receiver, value, attr, attrChanged);
522     }
523 }
524 
DeletePropertyInHolder()525 void ObjectOperator::DeletePropertyInHolder()
526 {
527     if (IsElement()) {
528         return DeleteElementInHolder();
529     }
530 
531     JSObject::DeletePropertyInternal(thread_, JSHandle<JSObject>(holder_), key_, GetIndex());
532 }
533 
AddProperty(const JSHandle<JSObject> & receiver,const JSHandle<JSTaggedValue> & value,PropertyAttributes attr)534 bool ObjectOperator::AddProperty(const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &value,
535                                  PropertyAttributes attr)
536 {
537     if (IsElement()) {
538         bool ret = JSObject::AddElementInternal(thread_, receiver, elementIndex_, value, attr);
539         bool isDict = receiver->GetJSHClass()->IsDictionaryElement();
540         SetFound(elementIndex_, value.GetTaggedValue(), attr.GetValue(), !isDict);
541         return ret;
542     }
543 
544     ResetState();
545     receiver_.Update(receiver.GetTaggedValue());
546     SetAttr(attr.GetValue());
547     AddPropertyInternal(value);
548     return true;
549 }
550 
WriteElement(const JSHandle<JSObject> & receiver,JSTaggedValue value) const551 void ObjectOperator::WriteElement(const JSHandle<JSObject> &receiver, JSTaggedValue value) const
552 {
553     ASSERT(IsElement() && GetIndex() < JSObject::MAX_ELEMENT_INDEX);
554 
555     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
556     if (!elements->IsDictionaryMode()) {
557         elements->Set(thread_, index_, value);
558         receiver->GetJSHClass()->UpdateRepresentation(value);
559         return;
560     }
561 
562     NumberDictionary *dictionary = NumberDictionary::Cast(elements);
563     dictionary->UpdateValue(thread_, GetIndex(), value);
564 }
565 
DeleteElementInHolder() const566 void ObjectOperator::DeleteElementInHolder() const
567 {
568     JSHandle<JSObject> obj(holder_);
569 
570     TaggedArray *elements = TaggedArray::Cast(obj->GetElements().GetTaggedObject());
571     if (!elements->IsDictionaryMode()) {
572         elements->Set(thread_, index_, JSTaggedValue::Hole());
573         JSObject::ElementsToDictionary(thread_, JSHandle<JSObject>(holder_));
574     } else {
575         JSHandle<NumberDictionary> dictHandle(thread_, elements);
576         JSHandle<NumberDictionary> newDict = NumberDictionary::Remove(thread_, dictHandle, GetIndex());
577         obj->SetElements(thread_, newDict);
578     }
579 }
580 
SetFound(uint32_t index,JSTaggedValue value,uint32_t attr,bool mode,bool transition)581 void ObjectOperator::SetFound(uint32_t index, JSTaggedValue value, uint32_t attr, bool mode, bool transition)
582 {
583     SetIndex(index);
584     SetValue(value);
585     SetFastMode(mode);
586     SetIsTransition(transition);
587     SetAttr(attr);
588 }
589 
UpdateFound(uint32_t index,uint32_t attr,bool mode,bool transition)590 void ObjectOperator::UpdateFound(uint32_t index, uint32_t attr, bool mode, bool transition)
591 {
592     SetIndex(index);
593     SetFastMode(mode);
594     SetIsTransition(transition);
595     SetAttr(attr);
596 }
597 
ResetState()598 void ObjectOperator::ResetState()
599 {
600     // index may used by element
601     SetIndex(NOT_FOUND_INDEX);
602     SetValue(JSTaggedValue::Undefined());
603     SetFastMode(false);
604     SetAttr(0);
605     SetIsOnPrototype(false);
606     SetHasReceiver(false);
607 }
608 
LookupElementInlinedProps(const JSHandle<JSObject> & obj)609 void ObjectOperator::LookupElementInlinedProps(const JSHandle<JSObject> &obj)
610 {
611     // if is js string, do special.
612     if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(obj.GetTaggedValue().GetTaggedObject())->IsString()) {
613         PropertyDescriptor desc(thread_);
614         bool status = JSPrimitiveRef::StringGetIndexProperty(thread_, obj, elementIndex_, &desc);
615         if (status) {
616             PropertyAttributes attr(desc);
617             SetFound(elementIndex_, desc.GetValue().GetTaggedValue(), attr.GetValue(), true);
618             return;
619         }
620     }
621     {
622         DISALLOW_GARBAGE_COLLECTION;
623         TaggedArray *elements = TaggedArray::Cast(obj->GetElements().GetTaggedObject());
624         if (elements->GetLength() == 0) {
625             return;  // Empty Array
626         }
627 
628         if (!elements->IsDictionaryMode()) {
629             if (elements->GetLength() <= elementIndex_) {
630                 return;
631             }
632 
633             JSTaggedValue value = elements->Get(elementIndex_);
634             if (value.IsHole()) {
635                 return;
636             }
637             SetFound(elementIndex_, value, PropertyAttributes::GetDefaultAttributes(), true);
638         } else {
639             NumberDictionary *dictionary = NumberDictionary::Cast(obj->GetElements().GetTaggedObject());
640             JSTaggedValue key(static_cast<int>(elementIndex_));
641             int entry = dictionary->FindEntry(key);
642             if (entry == -1) {
643                 return;
644             }
645 
646             uint32_t attr = dictionary->GetAttributes(entry).GetValue();
647             SetFound(entry, dictionary->GetValue(entry), attr, false);
648         }
649     }
650 }
651 
AddPropertyInternal(const JSHandle<JSTaggedValue> & value)652 void ObjectOperator::AddPropertyInternal(const JSHandle<JSTaggedValue> &value)
653 {
654     ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();
655     JSHandle<JSObject> obj(GetReceiver());
656     PropertyAttributes attr = GetAttr();
657     if (obj->IsJSGlobalObject()) {
658         JSMutableHandle<GlobalDictionary> dict(thread_, obj->GetProperties());
659         if (dict->GetLength() == 0) {
660             dict.Update(GlobalDictionary::Create(thread_));
661         }
662 
663         // Add PropertyBox to global dictionary
664         JSHandle<PropertyBox> cellHandle = factory->NewPropertyBox(key_);
665         cellHandle->SetValue(thread_, value.GetTaggedValue());
666         PropertyBoxType cellType = value->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT;
667         attr.SetBoxType(cellType);
668 
669         JSHandle<GlobalDictionary> properties =
670             GlobalDictionary::PutIfAbsent(thread_, dict, key_, JSHandle<JSTaggedValue>(cellHandle), attr);
671         obj->SetProperties(thread_, properties);
672         // index and fastMode is not essential for global obj;
673         SetFound(0, cellHandle.GetTaggedValue(), attr.GetValue(), true);
674         return;
675     }
676 
677     attr = FastRuntimeStub::AddPropertyByName(thread_, obj, key_, value, attr);
678     if (obj->GetJSHClass()->IsDictionaryMode()) {
679         SetFound(0, value.GetTaggedValue(), attr.GetValue(), false);
680     } else {
681         uint32_t index = attr.IsInlinedProps() ? attr.GetOffset() :
682                 attr.GetOffset() - obj->GetJSHClass()->GetInlinedProperties();
683         SetFound(index, value.GetTaggedValue(), attr.GetValue(), true, true);
684     }
685 }
686 
DefineSetter(const JSHandle<JSTaggedValue> & value)687 void ObjectOperator::DefineSetter(const JSHandle<JSTaggedValue> &value)
688 {
689     ASSERT(IsAccessorDescriptor());
690     JSHandle<AccessorData> accessor = JSHandle<AccessorData>::Cast(value_);
691     accessor->SetSetter(thread_, value.GetTaggedValue());
692     UpdateDataValue(JSHandle<JSObject>::Cast(receiver_), JSHandle<JSTaggedValue>::Cast(accessor), false);
693 }
694 
DefineGetter(const JSHandle<JSTaggedValue> & value)695 void ObjectOperator::DefineGetter(const JSHandle<JSTaggedValue> &value)
696 {
697     ASSERT(IsAccessorDescriptor());
698     JSHandle<AccessorData> accessor = JSHandle<AccessorData>::Cast(value_);
699     accessor->SetGetter(thread_, value.GetTaggedValue());
700     UpdateDataValue(JSHandle<JSObject>::Cast(receiver_), JSHandle<JSTaggedValue>::Cast(accessor), false);
701 }
702 }  // namespace panda::ecmascript
703