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