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