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