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