• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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/js_object.h"
17 #include "ecmascript/dfx/native_module_failure_info.h"
18 #include "ecmascript/global_dictionary-inl.h"
19 #include "ecmascript/ic/proto_change_details.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 #include "ecmascript/js_iterator.h"
22 #include "ecmascript/js_primitive_ref.h"
23 #include "ecmascript/object_fast_operator-inl.h"
24 #include "ecmascript/pgo_profiler/pgo_profiler.h"
25 #include "ecmascript/property_accessor.h"
26 #include "ecmascript/jspandafile/js_pandafile_manager.h"
27 
28 namespace panda::ecmascript {
29 using PGOProfiler = pgo::PGOProfiler;
PropertyAttributes(const PropertyDescriptor & desc)30 PropertyAttributes::PropertyAttributes(const PropertyDescriptor &desc)
31 {
32     DISALLOW_GARBAGE_COLLECTION;
33     if (desc.HasWritable()) {
34         SetWritable(desc.IsWritable());
35     }
36 
37     if (desc.HasEnumerable()) {
38         SetEnumerable(desc.IsEnumerable());
39     }
40 
41     if (desc.HasConfigurable()) {
42         SetConfigurable(desc.IsConfigurable());
43     }
44 
45     if (desc.IsAccessorDescriptor()) {
46         SetIsAccessor(true);
47     }
48     // internal accessor
49     if (desc.HasValue() && desc.GetValue()->IsAccessor()) {
50         SetIsAccessor(true);
51     }
52 }
53 
UpdateGrowStep(JSThread * thread,uint32_t step)54 void ThroughputJSObjectResizingStrategy::UpdateGrowStep(JSThread *thread, uint32_t step)
55 {
56     // 2 : multiple double
57     thread->SetPropertiesGrowStep(std::min(static_cast<uint32_t>(JSObjectResizingStrategy::PROPERTIES_GROW_SIZE * 2),
58                                            step));
59 }
60 
GetCallTarget() const61 Method *ECMAObject::GetCallTarget() const
62 {
63     const TaggedObject *obj = this;
64     ASSERT(JSTaggedValue(obj).IsJSFunctionBase() || JSTaggedValue(obj).IsJSProxy());
65 
66     JSTaggedValue value;
67     if (JSTaggedValue(obj).IsJSFunctionBase()) {
68         value = JSFunctionBase::ConstCast(obj)->GetMethod();
69     } else {
70         value = JSProxy::ConstCast(obj)->GetMethod();
71     }
72     return Method::Cast(value.GetTaggedObject());
73 }
74 
GrowElementsCapacity(const JSThread * thread,const JSHandle<JSObject> & obj,uint32_t capacity,bool highGrowth,bool isNew)75 JSHandle<TaggedArray> JSObject::GrowElementsCapacity(const JSThread *thread, const JSHandle<JSObject> &obj,
76                                                      uint32_t capacity, bool highGrowth, bool isNew)
77 {
78     uint32_t newCapacity = 0;
79     if (obj->IsJSArray()) {
80         uint32_t hint = JSHandle<JSArray>(obj)->GetHintLength();
81         newCapacity = ComputeElementCapacityWithHint(capacity, hint);
82     }
83     if (obj->IsJSSArray()) {
84         uint32_t hint = JSHandle<JSSharedArray>(obj)->GetHintLength();
85         newCapacity = ComputeElementCapacityWithHint(capacity, hint);
86     }
87     if (newCapacity == 0) {
88         newCapacity = highGrowth ? ComputeElementCapacityHighGrowth(capacity) :
89             ComputeElementCapacity(capacity, isNew);
90     }
91     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
92     JSHandle<TaggedArray> oldElements(thread, obj->GetElements());
93     uint32_t oldLength = oldElements->GetLength();
94 
95     ElementsKind kind = obj->GetClass()->GetElementsKind();
96     JSHandle<TaggedArray> newElements =
97         factory->CopyArray(oldElements, oldLength, newCapacity, JSTaggedValue::Hole(),
98                            obj->IsJSShared() ? MemSpaceType::SHARED_OLD_SPACE : MemSpaceType::SEMI_SPACE, kind);
99     obj->SetElements(thread, newElements);
100     if (thread->IsPGOProfilerEnable() && obj->IsJSArray()) {
101         auto trackInfo = JSHandle<JSArray>(obj)->GetTrackInfo();
102         thread->GetEcmaVM()->GetPGOProfiler()->UpdateTrackArrayLength(trackInfo, newCapacity);
103     }
104     return newElements;
105 }
106 
IterableToList(JSThread * thread,const JSHandle<JSTaggedValue> & items,JSTaggedValue method)107 JSHandle<JSTaggedValue> JSObject::IterableToList(JSThread *thread, const JSHandle<JSTaggedValue> &items,
108                                                  JSTaggedValue method)
109 {
110     // 1. If method is present, then
111     // a. Let iteratorRecord be ? GetIterator(items, sync, method).
112     // 2. Else,
113     // a. Let iteratorRecord be ? GetIterator(items, sync).
114     JSHandle<JSTaggedValue> iteratorRecord;
115     JSHandle<JSTaggedValue> methodHandle(thread, method);
116     if (!methodHandle->IsUndefined()) {
117         iteratorRecord = JSIterator::GetIterator(thread, items, methodHandle);
118         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
119     } else {
120         iteratorRecord = JSIterator::GetIterator(thread, items);
121         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
122     }
123     // 3. Let values be a new empty List.
124     // 4. Let next be true.
125     JSHandle<JSArray> array = JSHandle<JSArray>::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
126     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
127     JSHandle<JSTaggedValue> valuesList = JSHandle<JSTaggedValue>::Cast(array);
128     JSMutableHandle<JSTaggedValue> next(thread, JSTaggedValue::True());
129     // 5. Repeat, while next is not false,
130     // a. Set next to ? IteratorStep(iteratorRecord).
131     // b. If next is not false, then
132     // i. Let nextValue be ? IteratorValue(next).
133     // ii. Append nextValue to the end of the List values.
134     uint32_t k = 0;
135     while (!next->IsFalse()) {
136         next.Update(JSIterator::IteratorStep(thread, iteratorRecord).GetTaggedValue());
137         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
138         if (!next->IsFalse()) {
139             JSHandle<JSTaggedValue> nextValue(JSIterator::IteratorValue(thread, next));
140             RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
141             JSArray::FastSetPropertyByValue(thread, valuesList, k, nextValue);
142             RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
143             k++;
144         }
145     }
146     // 6. Return values.
147     return valuesList;
148 }
149 
IsRegExp(JSThread * thread,const JSHandle<JSTaggedValue> & argument)150 bool JSObject::IsRegExp(JSThread *thread, const JSHandle<JSTaggedValue> &argument)
151 {
152     if (!argument->IsECMAObject()) {
153         return false;
154     }
155     JSHandle<JSTaggedValue> matchSymbol = thread->GetEcmaVM()->GetGlobalEnv()->GetMatchSymbol();
156     JSTaggedValue isRegexp =  ObjectFastOperator::FastGetPropertyByValue(
157         thread, argument.GetTaggedValue(), matchSymbol.GetTaggedValue());
158     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
159     if (!isRegexp.IsUndefined()) {
160         return isRegexp.ToBoolean();
161     }
162     JSHandle<JSObject> argumentObj = JSHandle<JSObject>::Cast(argument);
163     return argumentObj->IsJSRegExp();
164 }
165 
TransitionToDictionary(const JSThread * thread,const JSHandle<JSObject> & receiver)166 JSHandle<NameDictionary> JSObject::TransitionToDictionary(const JSThread *thread, const JSHandle<JSObject> &receiver)
167 {
168     JSHandle<TaggedArray> array(thread, receiver->GetProperties());
169     JSHandle<JSHClass> jshclass(thread, receiver->GetJSHClass());
170     ASSERT(!jshclass->IsDictionaryMode());
171     uint32_t propNumber = jshclass->NumberOfProps();
172 
173     ASSERT(!jshclass->GetLayout().IsNull());
174     if (jshclass->IsJSShared()) {
175         THROW_TYPE_ERROR_AND_RETURN(const_cast<JSThread *>(thread),
176                                     "shared obj does not support changing or deleting attributes",
177                                     JSHandle<NameDictionary>());
178     }
179     JSHandle<LayoutInfo> layoutInfoHandle(thread, jshclass->GetLayout());
180     JSMutableHandle<NameDictionary> dict(
181         thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(propNumber)));
182     JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
183     JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
184     uint32_t numberInlinedProps = jshclass->GetInlinedProperties();
185     for (uint32_t i = 0; i < propNumber; i++) {
186         JSTaggedValue key = layoutInfoHandle->GetKey(i);
187         PropertyAttributes attr = layoutInfoHandle->GetAttr(i);
188         ASSERT(i == attr.GetOffset());
189         JSTaggedValue value;
190 
191         if (i < numberInlinedProps) {
192             value = receiver->GetPropertyInlinedPropsWithRep(i, attr);
193             // If delete a property in hclass which has subtyping info and not prototype, only set value as hole and
194             // not remove. When transition to dictionary, exclude it.
195             if (value.IsHole()) {
196                 continue;
197             }
198         } else {
199             value = array->Get(i - numberInlinedProps);
200         }
201 
202         attr.SetBoxType(PropertyBoxType::UNDEFINED);
203         valueHandle.Update(value);
204         keyHandle.Update(key);
205         JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
206         dict.Update(newDict);
207     }
208 
209     receiver->SetProperties(thread, dict);
210     ElementsKind oldKind = receiver->GetJSHClass()->GetElementsKind();
211     // change HClass
212     JSHClass::TransitionToDictionary(thread, receiver);
213     JSObject::TryMigrateToGenericKindForJSObject(thread, receiver, oldKind);
214 
215     // trim in-obj properties space
216     TrimInlinePropsSpace(thread, receiver, numberInlinedProps);
217 
218     return dict;
219 }
220 
ElementsToDictionary(const JSThread * thread,JSHandle<JSObject> obj)221 void JSObject::ElementsToDictionary(const JSThread *thread, JSHandle<JSObject> obj)
222 {
223     JSHandle<TaggedArray> elements(thread, obj->GetElements());
224     ASSERT(!obj->GetJSHClass()->IsDictionaryElement());
225     uint32_t length = elements->GetLength();
226     if (obj->IsJSShared()) {
227         THROW_TYPE_ERROR(const_cast<JSThread *>(thread),
228                          "shared obj does not support changing or deleting attributes");
229     }
230     JSMutableHandle<NumberDictionary> dict(thread, NumberDictionary::Create(thread));
231     auto attr = PropertyAttributes(PropertyAttributes::GetDefaultAttributes());
232     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
233     JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue ::Undefined());
234     for (uint32_t i = 0; i < length; i++) {
235         JSTaggedValue value = ElementAccessor::Get(obj, i);
236         if (value.IsHole()) {
237             continue;
238         }
239         key.Update(JSTaggedValue(i));
240         valueHandle.Update(value);
241         JSHandle<NumberDictionary> newDict = NumberDictionary::PutIfAbsent(thread, dict, key, valueHandle, attr);
242         dict.Update(newDict);
243     }
244     obj->SetElements(thread, dict);
245 
246     ElementsKind oldKind = obj->GetJSHClass()->GetElementsKind();
247     JSHClass::TransitionElementsToDictionary(thread, obj);
248     TryMigrateToGenericKindForJSObject(thread, obj, oldKind);
249 }
250 
ShouldOptimizeAsFastElements(const JSThread * thread,JSHandle<JSObject> obj)251 inline bool JSObject::ShouldOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj)
252 {
253     JSHandle<NumberDictionary> elements(thread, obj->GetElements());
254     uint32_t size = static_cast<uint32_t>(elements->Size());
255     for (uint32_t hashIndex = 0; hashIndex < size; hashIndex++) {
256         JSTaggedValue key = elements->GetKey(hashIndex);
257         if (key.IsUndefined() || key.IsHole()) {
258             continue;
259         }
260         PropertyAttributes attr = elements->GetAttributes(hashIndex);
261         if (!attr.IsDefaultAttributes()) {
262             return false;
263         }
264     }
265     return true;
266 }
267 
TryOptimizeAsFastElements(const JSThread * thread,JSHandle<JSObject> obj)268 void JSObject::TryOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj)
269 {
270     ASSERT(obj->GetJSHClass()->IsDictionaryElement() && obj->IsJSArray());
271     if (ShouldOptimizeAsFastElements(thread, obj)) {
272         uint32_t length = JSArray::Cast(*obj)->GetLength();
273         JSHandle<NumberDictionary> elements(thread, obj->GetElements());
274         uint32_t size = static_cast<uint32_t>(elements->Size());
275         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
276         JSHandle<TaggedArray> array = factory->NewTaggedArray(length);
277         for (uint32_t hashIndex = 0; hashIndex < size; hashIndex++) {
278             JSTaggedValue key = elements->GetKey(hashIndex);
279             JSTaggedValue value = elements->GetValue(hashIndex);
280             if (key.IsUndefined() || key.IsHole()) {
281                 continue;
282             }
283             ASSERT(key.IsInt());
284             uint32_t uintKey = static_cast<uint32_t>(key.GetInt());
285             if (uintKey < length) {
286                 array->Set(thread, uintKey, value);
287             }
288         }
289         obj->SetElements(thread, array);
290         JSHClass::OptimizeAsFastElements(thread, obj);
291     }
292 }
293 
OptimizeAsFastProperties(const JSThread * thread,JSHandle<JSObject> obj)294 void JSObject::OptimizeAsFastProperties(const JSThread *thread, JSHandle<JSObject> obj)
295 {
296     ASSERT(obj->GetJSHClass()->IsDictionaryMode());
297     // 1. Get NameDictionary properties
298     JSHandle<NameDictionary> properties(thread, obj->GetProperties());
299 
300     int numberOfProperties = properties->EntriesCount();
301     // Make sure we preserve enough capacity
302     if (numberOfProperties > static_cast<int>(PropertyAttributes::MAX_FAST_PROPS_CAPACITY)) {
303         return ;
304     }
305 
306     // 2. iteration indices
307     std::vector<int> indexOrder = properties->GetEnumerationOrder();
308     ASSERT(static_cast<int>(indexOrder.size()) == numberOfProperties);
309 
310     // 3. Change Hclass
311     int numberOfInlinedProps = static_cast<int>(obj->GetJSHClass()->GetInlinedProperties());
312     JSHClass::OptimizeAsFastProperties(thread, obj, indexOrder, true);
313 
314     // 4. New out-properties
315     int numberOfOutProperties = numberOfProperties - numberOfInlinedProps;
316     ASSERT(numberOfOutProperties >= 0);
317     JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(numberOfOutProperties);
318 
319     // 5. Fill properties
320     for (int i = 0; i < numberOfProperties; i++) {
321         JSTaggedValue value = properties->GetValue(indexOrder[i]);
322         if (i < numberOfInlinedProps) {
323             obj->SetPropertyInlinedPropsWithRep(thread, i, value);
324         } else {
325             array->Set(thread, i - numberOfInlinedProps, value);
326         }
327     }
328     obj->SetProperties(thread, array);
329 }
330 
SetSProperties(JSThread * thread,JSHandle<JSObject> obj,const std::vector<PropertyDescriptor> & descs)331 void JSObject::SetSProperties(JSThread *thread, JSHandle<JSObject> obj, const std::vector<PropertyDescriptor> &descs)
332 {
333     uint32_t length = descs.size();
334     JSMutableHandle<JSTaggedValue> propKey(thread, JSTaggedValue::Undefined());
335     JSMutableHandle<JSTaggedValue> propValue(thread, JSTaggedValue::Undefined());
336 
337     if (LIKELY(!obj->GetJSHClass()->IsDictionaryMode())) {
338         for (uint32_t i = 0; i < length; ++i) {
339             propValue.Update(descs[i].GetValue());
340             // note(lzl): IsSAccessor?
341             if (!propValue->IsSharedType() && !propValue->IsAccessor()) {
342                 THROW_TYPE_ERROR(thread, "The properties of sendable class must be sendable too.");
343             }
344             obj->SetPropertyInlinedProps(thread, i, propValue.GetTaggedValue());
345         }
346     } else {
347         JSMutableHandle<ecmascript::NameDictionary> dict(
348             thread, ecmascript::NameDictionary::CreateInSharedHeap(
349                 thread, ecmascript::NameDictionary::ComputeHashTableSize(length)));
350         for (uint32_t i = 0; i < length; i++) {
351             propKey.Update(descs[i].GetKey());
352             propValue.Update(descs[i].GetValue());
353             PropertyAttributes attr =
354                 PropertyAttributes::Default(descs[i].IsWritable(), descs[i].IsEnumerable(), descs[i].IsConfigurable());
355             JSHandle<ecmascript::NameDictionary> newDict =
356                 ecmascript::NameDictionary::PutIfAbsent(thread, dict, propKey, propValue, attr);
357             dict.Update(newDict);
358         }
359         obj->SetProperties(thread, dict);
360     }
361 }
362 
IsArrayLengthWritable(JSThread * thread,const JSHandle<JSObject> & receiver)363 bool JSObject::IsArrayLengthWritable(JSThread *thread, const JSHandle<JSObject> &receiver)
364 {
365     auto *hclass = receiver->GetJSHClass();
366     if (!hclass->IsDictionaryMode()) {
367         LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
368         PropertyAttributes attr(layoutInfo->GetAttr(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
369         return attr.IsWritable();
370     }
371     JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
372     ObjectOperator op(thread, receiver, lengthKey, OperatorType::OWN);
373     return op.GetAttr().IsWritable();
374 }
375 
AddElementInternal(JSThread * thread,const JSHandle<JSObject> & receiver,uint32_t index,const JSHandle<JSTaggedValue> & value,PropertyAttributes attr)376 bool JSObject::AddElementInternal(JSThread *thread, const JSHandle<JSObject> &receiver,
377                                   uint32_t index, const JSHandle<JSTaggedValue> &value,
378                                   PropertyAttributes attr)
379 {
380     ElementsKind kind = ElementsKind::NONE;
381     if (receiver->IsJSArray()) {
382         DISALLOW_GARBAGE_COLLECTION;
383         JSArray *arr = JSArray::Cast(*receiver);
384         uint32_t oldLength = arr->GetArrayLength();
385         if (index >= oldLength) {
386             if (!IsArrayLengthWritable(thread, receiver)) {
387                 return false;
388             }
389             arr->SetArrayLength(thread, index + 1);
390             if (index > oldLength) {
391                 kind = ElementsKind::HOLE;
392             }
393         }
394     }
395     if (receiver->IsJSSArray()) {
396         DISALLOW_GARBAGE_COLLECTION;
397         JSSharedArray *arr = JSSharedArray::Cast(*receiver);
398         uint32_t oldLength = arr->GetArrayLength();
399         if (index >= oldLength) {
400             JSHandle<JSTaggedValue> newLength(thread, JSTaggedValue(static_cast<uint32_t>(index + 1)));
401             JSSharedArray::LengthSetter(thread, receiver, newLength);
402             if (index > oldLength) {
403                 kind = ElementsKind::HOLE;
404             }
405         }
406     }
407     thread->NotifyStableArrayElementsGuardians(receiver, StableArrayChangeKind::NOT_PROTO);
408 
409     // check whether to convert to dictionary
410     if (receiver->GetJSHClass()->IsDictionaryElement() && receiver->IsJSArray()) {
411         JSArray *arr = JSArray::Cast(*receiver);
412         uint32_t capacity = arr->GetArrayLength();
413         TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
414         ASSERT(elements->IsDictionaryMode());
415         if (ShouldTransToFastElements(JSHandle<NumberDictionary>(thread, elements), capacity, index)) {
416             JSObject::TryOptimizeAsFastElements(thread, receiver);
417         }
418     }
419 
420     bool isDictionary = receiver->GetJSHClass()->IsDictionaryElement();
421     TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
422     if (isDictionary) {
423         ASSERT(elements->IsDictionaryMode());
424         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(static_cast<int32_t>(index)));
425         JSHandle<NumberDictionary> newDict =
426             NumberDictionary::Put(thread, JSHandle<NumberDictionary>(thread, elements), keyHandle, value, attr);
427         receiver->SetElements(thread, newDict);
428         return true;
429     }
430 
431     uint32_t capacity = elements->GetLength();
432     if (index >= capacity || !attr.IsDefaultAttributes()) {
433         if (!receiver->IsJSSArray() && (ShouldTransToDict(capacity, index) || !attr.IsDefaultAttributes())) {
434             JSObject::ElementsToDictionary(thread, receiver);
435             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
436             JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(static_cast<int32_t>(index)));
437             JSHandle<NumberDictionary> dict(thread, receiver->GetElements());
438             JSHandle<NumberDictionary> newKey = NumberDictionary::Put(thread, dict, keyHandle, value, attr);
439             receiver->SetElements(thread, newKey);
440             return true;
441         }
442         elements = *JSObject::GrowElementsCapacity(thread, receiver, index + 1);
443     }
444     bool needTransition = true;
445     if (receiver->IsJSShared()) {
446         needTransition = false;
447     }
448     ElementAccessor::Set(thread, receiver, index, value, needTransition, kind);
449     return true;
450 }
451 
DeletePropertyInternal(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,uint32_t index)452 void JSObject::DeletePropertyInternal(JSThread *thread, const JSHandle<JSObject> &obj,
453                                       const JSHandle<JSTaggedValue> &key, uint32_t index)
454 {
455     JSHandle<TaggedArray> array(thread, obj->GetProperties());
456 
457     if (obj->IsJSGlobalObject()) {
458         JSHandle<GlobalDictionary> dictHandle(thread, obj->GetProperties());
459         PropertyBox* box = dictHandle->GetBox(index);
460         box->Clear(thread);
461         JSHandle<GlobalDictionary> newDict = GlobalDictionary::Remove(thread, dictHandle, index);
462         obj->SetProperties(thread, newDict);
463         return;
464     }
465 
466     if (!array->IsDictionaryMode()) {
467         JSHandle<NameDictionary> dictHandle(TransitionToDictionary(thread, obj));
468         RETURN_IF_ABRUPT_COMPLETION(thread);
469         int entry = dictHandle->FindEntry(key.GetTaggedValue());
470         ASSERT(entry != -1);
471         JSHandle<NameDictionary> newDict = NameDictionary::Remove(thread, dictHandle, entry);
472         obj->SetProperties(thread, newDict);
473         return;
474     }
475 
476     JSHandle<NameDictionary> dictHandle(array);
477     JSHandle<NameDictionary> newDict = NameDictionary::Remove(thread, dictHandle, index);
478     obj->SetProperties(thread, newDict);
479 }
480 
GetAllKeys(const JSThread * thread,const JSHandle<JSObject> & obj,int offset,const JSHandle<TaggedArray> & keyArray)481 void JSObject::GetAllKeys(const JSThread *thread, const JSHandle<JSObject> &obj, int offset,
482                           const JSHandle<TaggedArray> &keyArray)
483 
484 {
485     TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
486     if (!array->IsDictionaryMode()) {
487         int end = static_cast<int>(obj->GetJSHClass()->NumberOfProps());
488         if (end > 0) {
489             LayoutInfo::Cast(obj->GetJSHClass()->GetLayout().GetTaggedObject())
490                 ->GetAllKeys(thread, end, offset, *keyArray, obj);
491         }
492         return;
493     }
494 
495     if (obj->IsJSGlobalObject()) {
496         GlobalDictionary *dict = GlobalDictionary::Cast(array);
497         return dict->GetAllKeys(thread, offset, *keyArray);
498     }
499 
500     NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
501     dict->GetAllKeys(thread, offset, *keyArray);
502 }
503 
GetAllKeysByFilter(const JSThread * thread,const JSHandle<JSObject> & obj,uint32_t & keyArrayEffectivelength,const JSHandle<TaggedArray> & keyArray,uint32_t filter)504 void JSObject::GetAllKeysByFilter(const JSThread *thread, const JSHandle<JSObject> &obj,
505                                   uint32_t &keyArrayEffectivelength,
506                                   const JSHandle<TaggedArray> &keyArray,
507                                   uint32_t filter)
508 {
509     TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
510     if (!array->IsDictionaryMode()) {
511         uint32_t numberOfProps = obj->GetJSHClass()->NumberOfProps();
512         if (numberOfProps > 0) {
513             LayoutInfo::Cast(obj->GetJSHClass()->GetLayout().GetTaggedObject())->
514                 GetAllKeysByFilter(thread, numberOfProps, keyArrayEffectivelength, *keyArray, obj, filter);
515         }
516         return;
517     }
518 
519     if (obj->IsJSGlobalObject()) {
520         GlobalDictionary *dict = GlobalDictionary::Cast(array);
521         return dict->GetAllKeysByFilter(thread, keyArrayEffectivelength, *keyArray, filter);
522     }
523 
524     NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
525     dict->GetAllKeysByFilter(thread, keyArrayEffectivelength, *keyArray, filter);
526 }
527 
528 // For Serialization use. Does not support JSGlobalObject
GetAllKeysForSerialization(const JSHandle<JSObject> & obj,std::vector<JSTaggedValue> & keyVector)529 void JSObject::GetAllKeysForSerialization(const JSHandle<JSObject> &obj, std::vector<JSTaggedValue> &keyVector)
530 {
531     DISALLOW_GARBAGE_COLLECTION;
532     ASSERT_PRINT(!obj->IsJSGlobalObject(), "Do not support get key of JSGlobal Object");
533     TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
534     if (!array->IsDictionaryMode()) {
535         int end = static_cast<int>(obj->GetJSHClass()->NumberOfProps());
536         if (end > 0) {
537             LayoutInfo::Cast(obj->GetJSHClass()->GetLayout().GetTaggedObject())->GetAllKeysForSerialization(end,
538                 keyVector);
539         }
540     } else {
541         NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
542         dict->GetAllKeysIntoVector(keyVector);
543     }
544 }
545 
GetAllEnumKeys(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t numOfKeys,uint32_t * keys)546 JSHandle<TaggedArray> JSObject::GetAllEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj,
547                                                uint32_t numOfKeys, uint32_t *keys)
548 {
549     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
550     if (obj->IsJSGlobalObject()) {
551         JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(numOfKeys);
552         GlobalDictionary *dict = GlobalDictionary::Cast(obj->GetProperties().GetTaggedObject());
553         dict->GetEnumAllKeys(thread, 0, *keyArray, keys);
554         return keyArray;
555     }
556 
557     TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
558     if (!array->IsDictionaryMode()) {
559         JSHClass *jsHclass = obj->GetJSHClass();
560         JSTaggedValue enumCache = jsHclass->GetEnumCache();
561         if (JSObject::GetEnumCacheKind(thread, enumCache) == EnumCacheKind::ONLY_OWN_KEYS) {
562             JSHandle<TaggedArray> cacheArray = JSHandle<TaggedArray>(thread, enumCache);
563             JSHandle<TaggedArray> keyArray = factory->CopyFromEnumCache(cacheArray);
564             *keys = keyArray->GetLength();
565             return keyArray;
566         }
567 
568         if (numOfKeys > 0) {
569             int end = static_cast<int>(jsHclass->NumberOfProps());
570             JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(numOfKeys + EnumCache::ENUM_CACHE_HEADER_SIZE);
571             LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject())
572                 ->GetAllEnumKeys(thread, end, EnumCache::ENUM_CACHE_HEADER_SIZE, keyArray, keys, obj);
573             JSObject::SetEnumCacheKind(thread, *keyArray, EnumCacheKind::ONLY_OWN_KEYS);
574             if (!JSTaggedValue(jsHclass).IsInSharedHeap()) {
575                 jsHclass->SetEnumCache(thread, keyArray.GetTaggedValue());
576             }
577             JSHandle<TaggedArray> newkeyArray = factory->CopyFromEnumCache(keyArray);
578             return newkeyArray;
579         }
580         return factory->EmptyArray();
581     }
582 
583     JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(numOfKeys);
584     NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
585     dict->GetAllEnumKeys(thread, 0, keyArray, keys);
586     return keyArray;
587 }
588 
GetAllEnumKeys(JSThread * thread,const JSHandle<JSObject> & obj,int offset,const JSHandle<TaggedArray> & keyArray)589 uint32_t JSObject::GetAllEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
590                                   const JSHandle<TaggedArray> &keyArray)
591 {
592     TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
593     uint32_t keys = 0;
594     if (!array->IsDictionaryMode()) {
595         JSHClass *jsHclass = obj->GetJSHClass();
596         int end = static_cast<int>(jsHclass->NumberOfProps());
597         if (end > 0) {
598             LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject())
599                 ->GetAllEnumKeys(thread, end, offset, keyArray, &keys, obj);
600         }
601         return keys;
602     }
603     if (obj->IsJSGlobalObject()) {
604         GlobalDictionary *dict = GlobalDictionary::Cast(obj->GetProperties().GetTaggedObject());
605         dict->GetEnumAllKeys(thread, offset, *keyArray, &keys);
606         return keys;
607     }
608 
609     NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
610     dict->GetAllEnumKeys(thread, offset, keyArray, &keys);
611     return keys;
612 }
613 
GetAllElementKeys(JSThread * thread,const JSHandle<JSObject> & obj,int offset,const JSHandle<TaggedArray> & keyArray)614 void JSObject::GetAllElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
615                                  const JSHandle<TaggedArray> &keyArray)
616 {
617     uint32_t elementIndex = 0;
618     if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
619         elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength() + static_cast<uint32_t>(offset);
620         for (uint32_t i = static_cast<uint32_t>(offset); i < elementIndex; ++i) {
621             auto key = base::NumberHelper::IntToEcmaString(thread, i);
622             keyArray->Set(thread, i, key);
623         }
624     }
625 
626     if (!ElementAccessor::IsDictionaryMode(obj)) {
627         uint32_t elementsLen = ElementAccessor::GetElementsLength(obj);
628         for (uint32_t i = 0, j = elementIndex; i < elementsLen; ++i) {
629             if (!ElementAccessor::Get(obj, i).IsHole()) {
630                 auto key = base::NumberHelper::IntToEcmaString(thread, i);
631                 keyArray->Set(thread, j++, key);
632             }
633         }
634     } else {
635         JSHandle<TaggedArray> elements(thread, obj->GetElements());
636         NumberDictionary::GetAllKeys(thread, JSHandle<NumberDictionary>(elements), elementIndex, keyArray);
637     }
638 }
639 
GetAllElementKeysByFilter(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<TaggedArray> & keyArray,uint32_t & keyArrayEffectiveLength,uint32_t filter)640 void JSObject::GetAllElementKeysByFilter(JSThread *thread,
641                                          const JSHandle<JSObject> &obj,
642                                          const JSHandle<TaggedArray> &keyArray,
643                                          uint32_t &keyArrayEffectiveLength,
644                                          uint32_t filter)
645 {
646     ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
647     uint32_t elementIndex = 0;
648 
649     // For strings attributes, only enumerable is true
650     if ((filter & NATIVE_ENUMERABLE) && obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
651         elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength();
652         for (uint32_t i = 0; i < elementIndex; ++i) {
653             keyArray->Set(thread, keyArrayEffectiveLength, JSTaggedValue(i));
654             keyArrayEffectiveLength++;
655         }
656     }
657 
658     JSHandle<JSTaggedValue> objValue(obj);
659 
660     if (!ElementAccessor::IsDictionaryMode(obj)) {
661         uint32_t elementsLen = ElementAccessor::GetElementsLength(obj);
662         for (uint32_t i = 0; i < elementsLen; ++i) {
663             if (!ElementAccessor::Get(obj, i).IsHole()) {
664                 ObjectOperator op(thread, objValue, i, OperatorType::OWN);
665                 bool bIgnore = FilterHelper::IgnoreKeyByFilter<ObjectOperator>(op, filter);
666                 if (bIgnore) {
667                     continue;
668                 }
669                 keyArray->Set(thread, keyArrayEffectiveLength, JSTaggedValue(i));
670                 keyArrayEffectiveLength++;
671             }
672         }
673     } else {
674         JSHandle<TaggedArray> elements(thread, obj->GetElements());
675         NumberDictionary::GetAllKeysByFilter(thread, JSHandle<NumberDictionary>(elements),
676             keyArrayEffectiveLength, keyArray, filter);
677     }
678 }
679 
GetALLElementKeysIntoVector(const JSThread * thread,const JSHandle<JSObject> & obj,std::vector<JSTaggedValue> & keyVector)680 void JSObject::GetALLElementKeysIntoVector(const JSThread *thread, const JSHandle<JSObject> &obj,
681                                            std::vector<JSTaggedValue> &keyVector)
682 {
683     if (!ElementAccessor::IsDictionaryMode(obj)) {
684         uint32_t elementsLen = ElementAccessor::GetElementsLength(obj);
685         for (uint32_t i = 0; i < elementsLen; ++i) {
686             if (!ElementAccessor::Get(obj, i).IsHole()) {
687                 keyVector.emplace_back(JSTaggedValue(i));
688             }
689         }
690     } else {
691         JSHandle<TaggedArray> elements(thread, obj->GetElements());
692         JSHandle<NumberDictionary> dict = JSHandle<NumberDictionary>::Cast(elements);
693         dict->GetAllKeysIntoVector(keyVector);
694     }
695 }
696 
GetEnumElementKeys(JSThread * thread,const JSHandle<JSObject> & obj,int offset,uint32_t numOfElements,uint32_t * keys)697 JSHandle<TaggedArray> JSObject::GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
698                                                    uint32_t numOfElements, uint32_t *keys)
699 {
700     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
701     JSHandle<TaggedArray> elementArray = factory->NewTaggedArray(numOfElements);
702     CollectEnumElementsAlongProtoChain(thread, obj, offset, elementArray, keys);
703     return elementArray;
704 }
705 
CollectEnumElementsAlongProtoChain(JSThread * thread,const JSHandle<JSObject> & obj,int offset,JSHandle<TaggedArray> elementArray,uint32_t * keys,int32_t lastLength)706 void JSObject::CollectEnumElementsAlongProtoChain(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
707                                                   JSHandle<TaggedArray> elementArray, uint32_t *keys,
708                                                   int32_t lastLength)
709 {
710     uint32_t elementIndex = static_cast<uint32_t>(offset);
711     JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
712 
713     if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
714         uint32_t strLen = JSPrimitiveRef::Cast(*obj)->GetStringLength();
715         for (uint32_t i = 0; i < strLen; ++i) {
716             keyHandle.Update(base::NumberHelper::IntToEcmaString(thread, i));
717             elementArray->Set(thread, elementIndex, keyHandle);
718             elementIndex++;
719         }
720         *keys += strLen;
721     }
722 
723     if (!ElementAccessor::IsDictionaryMode(obj)) {
724         JSHandle<TaggedQueue> emptyQueue = thread->GetEcmaVM()->GetFactory()->GetEmptyTaggedQueue();
725         uint32_t elementsLen = ElementAccessor::GetElementsLength(obj);
726         uint32_t preElementIndex = elementIndex;
727         for (uint32_t i = 0; i < elementsLen; ++i) {
728             if (ElementAccessor::Get(obj, i).IsHole()) {
729                 continue;
730             }
731             keyHandle.Update(base::NumberHelper::IntToEcmaString(thread, i));
732             bool isDuplicated = IsDepulicateKeys(thread, elementArray, lastLength, emptyQueue, keyHandle);
733             if (isDuplicated) {
734                 continue;
735             }
736             elementArray->Set(thread, elementIndex, keyHandle);
737             elementIndex++;
738         }
739         *keys += (elementIndex - preElementIndex);
740     } else {
741         JSHandle<TaggedArray> arr(thread, obj->GetElements());
742         NumberDictionary::GetAllEnumKeys(
743             thread, JSHandle<NumberDictionary>(arr), elementIndex, elementArray, keys, lastLength);
744     }
745 }
746 
GetEnumElementKeys(JSThread * thread,const JSHandle<JSObject> & obj,int offset,const JSHandle<TaggedArray> & keyArray)747 void JSObject::GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
748                                   const JSHandle<TaggedArray> &keyArray)
749 {
750     uint32_t elementIndex = 0;
751     if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
752         elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength() + static_cast<uint32_t>(offset);
753         for (uint32_t i = static_cast<uint32_t>(offset); i < elementIndex; ++i) {
754             auto key = base::NumberHelper::IntToEcmaString(thread, i);
755             keyArray->Set(thread, i, key);
756         }
757     }
758 
759     if (!ElementAccessor::IsDictionaryMode(obj)) {
760         uint32_t elementsLen = ElementAccessor::GetElementsLength(obj);
761         for (uint32_t i = 0, j = elementIndex; i < elementsLen; ++i) {
762             if (!ElementAccessor::Get(obj, i).IsHole()) {
763                 auto key = base::NumberHelper::IntToEcmaString(thread, i);
764                 keyArray->Set(thread, j++, key);
765             }
766         }
767     } else {
768         JSHandle<TaggedArray> elements(thread, obj->GetElements());
769         uint32_t keys = 0;
770         NumberDictionary::GetAllEnumKeys(thread, JSHandle<NumberDictionary>(elements), elementIndex, keyArray, &keys);
771     }
772 }
773 
GetNumberOfEnumKeys() const774 std::pair<uint32_t, uint32_t> JSObject::GetNumberOfEnumKeys() const
775 {
776     DISALLOW_GARBAGE_COLLECTION;
777     TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
778     if (!array->IsDictionaryMode()) {
779         int end = static_cast<int>(GetJSHClass()->NumberOfProps());
780         if (end > 0) {
781             LayoutInfo *layout = LayoutInfo::Cast(GetJSHClass()->GetLayout().GetTaggedObject());
782             return layout->GetNumOfEnumKeys(end, this);
783         }
784         return std::make_pair(0, 0);
785     }
786     if (IsJSGlobalObject()) {
787         GlobalDictionary *dict = GlobalDictionary::Cast(array);
788         return dict->GetNumOfEnumKeys();
789     }
790 
791     NameDictionary *dict = NameDictionary::Cast(GetProperties().GetTaggedObject());
792     return dict->GetNumOfEnumKeys();
793 }
794 
GetNumberOfKeys()795 uint32_t JSObject::GetNumberOfKeys()
796 {
797     DISALLOW_GARBAGE_COLLECTION;
798     TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
799 
800     if (!array->IsDictionaryMode()) {
801         return GetJSHClass()->NumberOfProps();
802     }
803 
804     return NameDictionary::Cast(array)->EntriesCount();
805 }
806 
GlobalSetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool mayThrow)807 bool JSObject::GlobalSetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key,
808                                  const JSHandle<JSTaggedValue> &value, bool mayThrow)
809 {
810     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
811 
812     ObjectOperator op(thread, key);
813     if (!op.IsFound()) {
814         PropertyAttributes attr = PropertyAttributes::Default(true, true, false);
815         op.SetAttr(attr);
816     }
817     return SetProperty(&op, value, mayThrow);
818 }
819 
GetNumberOfElements()820 uint32_t JSObject::GetNumberOfElements()
821 {
822     DISALLOW_GARBAGE_COLLECTION;
823     uint32_t numOfElements = 0;
824     if (IsJSPrimitiveRef() && JSPrimitiveRef::Cast(this)->IsString()) {
825         numOfElements = JSPrimitiveRef::Cast(this)->GetStringLength();
826     }
827 
828     if (!ElementAccessor::IsDictionaryMode(this)) {
829         uint32_t elementsLen = ElementAccessor::GetElementsLength(this);
830         for (uint32_t i = 0; i < elementsLen; ++i) {
831             if (!ElementAccessor::Get(this, i).IsHole()) {
832                 numOfElements++;
833             }
834         }
835     } else {
836         TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
837         numOfElements += static_cast<uint32_t>(NumberDictionary::Cast(elements)->EntriesCount());
838     }
839 
840     return numOfElements;
841 }
842 
843 // 9.1.9 [[Set]] ( P, V, Receiver)
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)844 bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
845                            const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
846 {
847     ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
848     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
849 
850     // 2 ~ 4 findProperty in Receiver, Obj and its parents
851     ObjectOperator op(thread, obj, receiver, key);
852     return SetProperty(&op, value, mayThrow);
853 }
854 
SetProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool mayThrow)855 bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
856                            const JSHandle<JSTaggedValue> &value, bool mayThrow)
857 {
858     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid JSObject");
859     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
860 
861     ObjectOperator op(thread, obj, key);
862     return SetProperty(&op, value, mayThrow);
863 }
864 
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool mayThrow,SCheckMode sCheckMode)865 bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
866                            const JSHandle<JSTaggedValue> &value, bool mayThrow, SCheckMode sCheckMode)
867 {
868     ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
869     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
870 
871     if (obj->IsJSSharedArray()) {
872         return JSSharedArray::SetProperty(thread, obj, key, value, mayThrow, sCheckMode);
873     }
874     // 2 ~ 4 findProperty in Receiver, Obj and its parents
875     ObjectOperator op(thread, obj, key);
876     return SetProperty(&op, value, mayThrow);
877 }
878 
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t index,const JSHandle<JSTaggedValue> & value,bool mayThrow)879 bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index,
880                            const JSHandle<JSTaggedValue> &value, bool mayThrow)
881 {
882     ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
883 
884     ObjectOperator op(thread, obj, index);
885     return SetProperty(&op, value, mayThrow);
886 }
887 
SetPropertyForDataDescriptorProxy(JSThread * thread,ObjectOperator * op,const JSHandle<JSTaggedValue> & value,JSHandle<JSTaggedValue> & receiver)888 bool JSObject::SetPropertyForDataDescriptorProxy(JSThread *thread, ObjectOperator *op,
889                                                  const JSHandle<JSTaggedValue> &value,
890                                                  JSHandle<JSTaggedValue> &receiver)
891 {
892     ASSERT(receiver->IsJSProxy());
893     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
894     if (op->IsElement()) {
895         key.Update(JSTaggedValue(op->GetElementIndex()));
896     } else {
897         key.Update(op->GetKey().GetTaggedValue());
898     }
899 
900     PropertyDescriptor existDesc(thread);
901     JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>::Cast(receiver), key, existDesc);
902     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
903     if (!existDesc.IsEmpty()) {
904         if (existDesc.IsAccessorDescriptor()) {
905             return false;
906         }
907 
908         if (!existDesc.IsWritable()) {
909             return false;
910         }
911 
912         PropertyDescriptor valueDesc(thread, value);
913         return JSProxy::DefineOwnProperty(thread, JSHandle<JSProxy>::Cast(receiver), key, valueDesc);
914     }
915     return CreateDataProperty(thread, JSHandle<JSObject>(receiver), key, value);
916 }
917 
SetPropertyForDataDescriptor(ObjectOperator * op,const JSHandle<JSTaggedValue> & value,JSHandle<JSTaggedValue> & receiver,bool mayThrow,bool isInternalAccessor)918 bool JSObject::SetPropertyForDataDescriptor(ObjectOperator *op, const JSHandle<JSTaggedValue> &value,
919                                             JSHandle<JSTaggedValue> &receiver, bool mayThrow, bool isInternalAccessor)
920 {
921     JSThread *thread = op->GetThread();
922     if (!op->IsWritable()) {
923         if (mayThrow) {
924             THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetReadOnlyProperty), false);
925         }
926         return false;
927     }
928 
929     if (!receiver->IsECMAObject()) {
930         if (mayThrow) {
931             THROW_TYPE_ERROR_AND_RETURN(thread, "Receiver is not a JSObject", false);
932         }
933         return false;
934     }
935     if (op->IsFound() && receiver->IsJSShared()) {
936         if (!ClassHelper::MatchFieldType(op->GetSharedFieldType(), value.GetTaggedValue())) {
937             if (mayThrow) {
938                 THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), false);
939             }
940             return false;
941         }
942     }
943 
944     if (receiver->IsJSProxy()) {
945         return SetPropertyForDataDescriptorProxy(thread, op, value, receiver);
946     }
947 
948     // 5e. If existingDescriptor is not undefined, then
949     bool hasReceiver = false;
950     if (op->HasReceiver()) {
951         op->ReLookupPropertyInReceiver();
952         isInternalAccessor = false;
953         if (op->IsAccessorDescriptor()) {
954             JSTaggedValue ret = ShouldGetValueFromBox(op);
955             isInternalAccessor = AccessorData::Cast(ret.GetTaggedObject())->IsInternal();
956         }
957         hasReceiver = true;
958     }
959     bool isSuccess = true;
960     if (op->IsFound() && !op->IsOnPrototype()) {
961         // i. If IsAccessorDescriptor(existingDescriptor) is true, return false.
962         if (op->IsAccessorDescriptor() && !isInternalAccessor) {
963             return false;
964         }
965 
966         // ii. If existingDescriptor.[[Writable]] is false, return false.
967         if (!op->IsWritable()) {
968             if (mayThrow) {
969                 THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetReadOnlyProperty), false);
970             }
971             return false;
972         }
973         if (hasReceiver && receiver->IsJSShared() &&
974             !ClassHelper::MatchFieldType(op->GetSharedFieldType(), value.GetTaggedValue())) {
975             if (mayThrow) {
976                 THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), false);
977             }
978             return false;
979         }
980         isSuccess = op->UpdateDataValue(JSHandle<JSObject>(receiver), value, isInternalAccessor, mayThrow);
981         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, isSuccess);
982     } else {
983         // 5f. Else if Receiver does not currently have a property P, Return CreateDataProperty(Receiver, P, V).
984         // fixme(hzzhouzebin) this makes SharedArray's frozen no sense.
985         if (!receiver->IsExtensible(thread) && !(receiver->IsJSSharedArray() && op->IsElement())) {
986             if (mayThrow) {
987                 THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetPropertyWhenNotExtensible), false);
988             }
989             return false;
990         }
991         if (hasReceiver || isInternalAccessor) {
992             return op->AddProperty(JSHandle<JSObject>(receiver), value, PropertyAttributes::Default());
993         } else if (op->IsFound() && receiver.GetTaggedValue() != op->GetHolder().GetTaggedValue()) {
994             return op->AddProperty(JSHandle<JSObject>(receiver), value, PropertyAttributes::Default());
995         } else {
996             return op->AddProperty(JSHandle<JSObject>(receiver), value, op->GetAttr());
997         }
998     }
999     return isSuccess;
1000 }
1001 
SetProperty(ObjectOperator * op,const JSHandle<JSTaggedValue> & value,bool mayThrow)1002 bool JSObject::SetProperty(ObjectOperator *op, const JSHandle<JSTaggedValue> &value, bool mayThrow)
1003 {
1004     JSThread *thread = op->GetThread();
1005     op->UpdateDetector();
1006 
1007     JSHandle<JSTaggedValue> receiver = op->GetReceiver();
1008     JSHandle<JSTaggedValue> holder = op->GetHolder();
1009     if (holder->IsJSProxy()) {
1010         if (op->IsElement()) {
1011             JSHandle<JSTaggedValue> key(thread, JSTaggedValue(op->GetElementIndex()));
1012             return JSProxy::SetProperty(thread, JSHandle<JSProxy>::Cast(holder), key, value, receiver, mayThrow);
1013         }
1014         return JSProxy::SetProperty(thread, JSHandle<JSProxy>::Cast(holder), op->GetKey(), value, receiver, mayThrow);
1015     }
1016 
1017     // When op is not found and is not set extra attributes
1018     if (!op->IsFound() && op->IsPrimitiveAttr()) {
1019         op->SetAsDefaultAttr();
1020     }
1021 
1022     bool isInternalAccessor = false;
1023     if (op->IsAccessorDescriptor()) {
1024         JSTaggedValue ret = ShouldGetValueFromBox(op);
1025         isInternalAccessor = AccessorData::Cast(ret.GetTaggedObject())->IsInternal();
1026     }
1027 
1028     // 5. If IsDataDescriptor(ownDesc) is true, then
1029     if (!op->IsAccessorDescriptor() || isInternalAccessor) {
1030         return SetPropertyForDataDescriptor(op, value, receiver, mayThrow, isInternalAccessor);
1031     }
1032     // 6. Assert: IsAccessorDescriptor(ownDesc) is true.
1033     ASSERT(op->IsAccessorDescriptor());
1034     // 8. If setter is undefined, return false.
1035     JSTaggedValue ret = ShouldGetValueFromBox(op);
1036     AccessorData *accessor = AccessorData::Cast(ret.GetTaggedObject());
1037     return CallSetter(thread, *accessor, receiver, value, mayThrow);
1038 }
1039 
CallSetter(JSThread * thread,const AccessorData & accessor,const JSHandle<JSTaggedValue> & receiver,const JSHandle<JSTaggedValue> & value,bool mayThrow)1040 bool JSObject::CallSetter(JSThread *thread, const AccessorData &accessor, const JSHandle<JSTaggedValue> &receiver,
1041                           const JSHandle<JSTaggedValue> &value, bool mayThrow)
1042 {
1043     if (UNLIKELY(accessor.IsInternal())) {
1044         return accessor.CallInternalSet(thread, JSHandle<JSObject>::Cast(receiver), value, mayThrow);
1045     }
1046     JSTaggedValue setter = accessor.GetSetter();
1047     // 8. If setter is undefined, return false.
1048     if (setter.IsUndefined()) {
1049         if (mayThrow) {
1050             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property when setter is undefined", false);
1051         }
1052         return false;
1053     }
1054 
1055     JSHandle<JSTaggedValue> func(thread, setter);
1056     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1057     EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, receiver, undefined, 1);
1058     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1059     info->SetCallArg(value.GetTaggedValue());
1060     JSFunction::Call(info);
1061 
1062     // 10. ReturnIfAbrupt(setterResult).
1063     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1064 
1065     return true;
1066 }
1067 
CallGetter(JSThread * thread,const AccessorData * accessor,const JSHandle<JSTaggedValue> & receiver)1068 JSTaggedValue JSObject::CallGetter(JSThread *thread, const AccessorData *accessor,
1069                                    const JSHandle<JSTaggedValue> &receiver)
1070 {
1071     JSTaggedValue getter = accessor->GetGetter();
1072     // 7. If getter is undefined, return undefined.
1073     if (getter.IsUndefined()) {
1074         return JSTaggedValue::Undefined();
1075     }
1076 
1077     JSHandle<JSTaggedValue> func(thread, getter);
1078     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1079     EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, receiver, undefined, 0);
1080     JSTaggedValue res = JSFunction::Call(info);
1081     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1082     return res;
1083 }
1084 
1085 // 9.1.8 [[Get]] (P, Receiver)
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)1086 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1087                                       const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
1088 {
1089     ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
1090     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1091 
1092     ObjectOperator op(thread, obj, receiver, key);
1093     return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
1094 }
1095 
GetProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key)1096 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSObject> &obj,
1097                                       const JSHandle<JSTaggedValue> &key)
1098 {
1099     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid JSObject");
1100     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1101 
1102     ObjectOperator op(thread, obj, key);
1103     return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
1104 }
1105 
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,SCheckMode sCheckMode)1106 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1107                                       const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode)
1108 {
1109     ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
1110     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1111     if (obj->IsJSSharedArray()) {
1112         return JSSharedArray::GetProperty(thread, obj, key, sCheckMode);
1113     }
1114     ObjectOperator op(thread, obj, key);
1115     return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
1116 }
1117 
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t index)1118 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index)
1119 {
1120     ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
1121 
1122     ObjectOperator op(thread, obj, index);
1123     return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
1124 }
1125 
GetPropertyFromGlobal(JSThread * thread,const JSHandle<JSTaggedValue> & key)1126 OperationResult JSObject::GetPropertyFromGlobal(JSThread *thread, const JSHandle<JSTaggedValue> &key)
1127 {
1128     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1129 
1130     ObjectOperator op(thread, key);
1131     return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
1132 }
1133 
GetGlobalPropertyBox(JSTaggedValue key)1134 PropertyBox* JSObject::GetGlobalPropertyBox(JSTaggedValue key)
1135 {
1136     ASSERT(IsJSGlobalObject());
1137     auto dict = GlobalDictionary::Cast(GetProperties().GetTaggedObject());
1138     auto entry = dict->FindEntry(key);
1139     if (entry == -1) {
1140         return nullptr;
1141     }
1142     return dict->GetBox(entry);
1143 }
1144 
GetGlobalPropertyBox(JSThread * thread,const std::string & key)1145 PropertyBox* JSObject::GetGlobalPropertyBox(JSThread *thread, const std::string& key)
1146 {
1147     auto factory = thread->GetEcmaVM()->GetFactory();
1148     auto keyValue = factory->NewFromUtf8(key).GetTaggedValue();
1149     return GetGlobalPropertyBox(keyValue);
1150 }
1151 
GetProperty(JSThread * thread,ObjectOperator * op)1152 JSTaggedValue JSObject::GetProperty(JSThread *thread, ObjectOperator *op)
1153 {
1154     JSHandle<JSTaggedValue> receiver = op->GetReceiver();
1155     JSHandle<JSTaggedValue> holder = op->GetHolder();
1156     if (receiver->IsNativeModuleFailureInfo()) {
1157         JSTaggedValue failureInfo = JSHandle<NativeModuleFailureInfo>::Cast(receiver)->GetArkNativeModuleFailureInfo();
1158         THROW_REFERENCE_ERROR_AND_RETURN(thread, ConvertToString(failureInfo).c_str(), JSTaggedValue::Undefined());
1159     }
1160     if (holder->IsJSProxy()) {
1161         if (op->IsElement()) {
1162             JSHandle<JSTaggedValue> key(thread, JSTaggedValue(op->GetElementIndex()));
1163             return JSProxy::GetProperty(thread, JSHandle<JSProxy>::Cast(holder), key, receiver)
1164                 .GetValue()
1165                 .GetTaggedValue();
1166         }
1167         return JSProxy::GetProperty(thread, JSHandle<JSProxy>::Cast(holder), op->GetKey(), receiver)
1168             .GetValue()
1169             .GetTaggedValue();
1170     }
1171 
1172     // 4. If desc is undefined, then
1173     if (!op->IsFound()) {
1174         // 4c. If obj and parent is null, return undefined.
1175         return JSTaggedValue::Undefined();
1176     }
1177     // 5. If IsDataDescriptor(desc) is true, return desc.[[Value]]
1178     JSTaggedValue ret = ShouldGetValueFromBox(op);
1179     if (!op->IsAccessorDescriptor()) {
1180         return ret;
1181     }
1182 
1183     // 6. Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].
1184     AccessorData *accessor = AccessorData::Cast(ret.GetTaggedObject());
1185     // 8. Return Call(getter, Receiver).
1186     if (UNLIKELY(accessor->IsInternal())) {
1187         return accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(holder));
1188     }
1189     return CallGetter(thread, accessor, receiver);
1190 }
1191 
DeleteProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,SCheckMode sCheckMode)1192 bool JSObject::DeleteProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1193                               SCheckMode sCheckMode)
1194 {
1195     // 1. Assert: IsPropertyKey(P) is true.
1196     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1197     // 2. Let desc be O.[[GetOwnProperty]](P).
1198     ObjectOperator op(thread, JSHandle<JSTaggedValue>(obj), key, OperatorType::OWN);
1199 
1200     // 4. If desc is undefined, return true.
1201     if (!op.IsFound()) {
1202         return true;
1203     }
1204     // 5. If desc.[[Configurable]] is true, then
1205     // a. Remove the own property with name P from O.
1206     // b. Return true.
1207     // 6. Return false.
1208     if (op.IsConfigurable() || sCheckMode == SCheckMode::SKIP) {
1209         op.DeletePropertyInHolder();
1210         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1211         obj->GetClass()->SetHasDeleteProperty(true);
1212         return true;
1213     }
1214     return false;
1215 }
1216 
GetOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1217 bool JSObject::GetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1218                               PropertyDescriptor &desc)
1219 {
1220     return OrdinaryGetOwnProperty(thread, obj, key, desc);
1221 }
1222 
GlobalGetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1223 bool JSObject::GlobalGetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1224 {
1225     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1226     ObjectOperator op(thread, key, OperatorType::OWN);
1227 
1228     if (!op.IsFound()) {
1229         return false;
1230     }
1231 
1232     op.ToPropertyDescriptor(desc);
1233 
1234     if (desc.HasValue()) {
1235         PropertyBox *cell = PropertyBox::Cast(desc.GetValue().GetTaggedValue().GetTaggedObject());
1236         JSHandle<JSTaggedValue> valueHandle(thread, cell->GetValue());
1237         desc.SetValue(valueHandle);
1238     }
1239     ASSERT(!desc.GetValue()->IsInternalAccessor());
1240     return true;
1241 }
1242 
OrdinaryGetOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1243 bool JSObject::OrdinaryGetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
1244                                       const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1245 {
1246     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1247     ObjectOperator op(thread, JSHandle<JSTaggedValue>(obj), key, OperatorType::OWN);
1248 
1249     if (!op.IsFound()) {
1250         return false;
1251     }
1252 
1253     op.ToPropertyDescriptor(desc);
1254 
1255     if (desc.HasValue() && obj->IsJSGlobalObject()) {
1256         JSTaggedValue val = desc.GetValue().GetTaggedValue();
1257         if (val.IsPropertyBox()) {
1258             PropertyBox *cell = PropertyBox::Cast(val.GetTaggedObject());
1259             JSHandle<JSTaggedValue> valueHandle(thread, cell->GetValue());
1260             desc.SetValue(valueHandle);
1261         }
1262     }
1263 
1264     return true;
1265 }
1266 
DefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc,SCheckMode sCheckMode)1267 bool JSObject::DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1268                                  const PropertyDescriptor &desc, SCheckMode sCheckMode)
1269 {
1270     return OrdinaryDefineOwnProperty(thread, obj, key, desc, sCheckMode);
1271 }
1272 
DefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const PropertyDescriptor & desc,SCheckMode sCheckMode)1273 bool JSObject::DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1274                                  const PropertyDescriptor &desc, SCheckMode sCheckMode)
1275 {
1276     return OrdinaryDefineOwnProperty(thread, obj, index, desc, sCheckMode);
1277 }
1278 
1279 // 9.1.6.1 OrdinaryDefineOwnProperty (O, P, Desc)
OrdinaryDefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc,SCheckMode sCheckMode)1280 bool JSObject::OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
1281                                          const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc,
1282                                          SCheckMode sCheckMode)
1283 {
1284     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1285     // 1. Let current be O.[[GetOwnProperty]](P).
1286     JSHandle<JSTaggedValue> objValue(obj);
1287     ObjectOperator op(thread, objValue, key, OperatorType::OWN);
1288 
1289     bool extensible = obj->IsExtensible();
1290     // make extensible for shared array to add element.
1291     if (obj->IsJSSArray() && op.IsElement()) {
1292         extensible = true;
1293     }
1294     PropertyDescriptor current(thread);
1295     op.ToPropertyDescriptor(current);
1296     // 4. Return ValidateAndApplyPropertyDescriptor(O, P, extensible, Desc, current).
1297     return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current, sCheckMode);
1298 }
1299 
OrdinaryDefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const PropertyDescriptor & desc,SCheckMode sCheckMode)1300 bool JSObject::OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1301                                          const PropertyDescriptor &desc, SCheckMode sCheckMode)
1302 {
1303     JSHandle<JSTaggedValue> objValue(obj);
1304     ObjectOperator op(thread, objValue, index, OperatorType::OWN);
1305 
1306     bool extensible = obj->IsExtensible();
1307     PropertyDescriptor current(thread);
1308     op.ToPropertyDescriptor(current);
1309     return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current, sCheckMode);
1310 }
1311 
ValidateDataDescriptorWhenConfigurable(ObjectOperator * op,const PropertyDescriptor & desc,const PropertyDescriptor & current,SCheckMode sCheckMode)1312 bool JSObject::ValidateDataDescriptorWhenConfigurable(ObjectOperator *op, const PropertyDescriptor &desc,
1313                                                       const PropertyDescriptor &current, SCheckMode sCheckMode)
1314 {
1315     // 8a i. Return false, if the [[Writable]] field of current is false and the [[Writable]] field of Desc
1316     // is true.
1317     if (!current.IsWritable() && desc.HasWritable() && desc.IsWritable()) {
1318         return false;
1319     }
1320     // 8a ii. If the [[Writable]] field of current is false, then
1321     if (!current.IsWritable()) {
1322         if (desc.HasValue() && !JSTaggedValue::SameValue(current.GetValue(), desc.GetValue())) {
1323             return false;
1324         }
1325     }
1326     if (op->HasHolder() && op->GetHolder()->IsJSShared() && (sCheckMode == SCheckMode::CHECK)) {
1327         if (!desc.HasValue()) {
1328             THROW_TYPE_ERROR_AND_RETURN(op->GetThread(), GET_MESSAGE_STRING(UpdateSendableAttributes), false);
1329         }
1330         if (!ClassHelper::MatchFieldType(current.GetSharedFieldType(), desc.GetValue().GetTaggedValue())) {
1331             THROW_TYPE_ERROR_AND_RETURN(op->GetThread(), GET_MESSAGE_STRING(SetTypeMismatchedSharedProperty), false);
1332         }
1333     }
1334     return true;
1335 }
1336 
1337 // 9.1.6.3 ValidateAndApplyPropertyDescriptor (O, P, extensible, Desc, current)
ValidateAndApplyPropertyDescriptor(ObjectOperator * op,bool extensible,const PropertyDescriptor & desc,const PropertyDescriptor & current,SCheckMode sCheckMode)1338 bool JSObject::ValidateAndApplyPropertyDescriptor(ObjectOperator *op, bool extensible, const PropertyDescriptor &desc,
1339                                                   const PropertyDescriptor &current, SCheckMode sCheckMode)
1340 {
1341     // 2. If current is undefined, then
1342     if (current.IsEmpty()) {
1343         // 2a. If extensible is false, return false.
1344         if (!(extensible || (op->HasHolder() && op->GetHolder()->IsJSShared() && sCheckMode == SCheckMode::SKIP))) {
1345             return false;
1346         }
1347         if (!op->HasHolder()) {
1348             return true;
1349         }
1350 
1351         // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then
1352         PropertyAttributes attr(desc);
1353         bool success = false;
1354         if (!desc.IsAccessorDescriptor()) {
1355             op->UpdateDetector();
1356             success = op->AddPropertyInHolder(desc.GetValue(), attr);
1357         } else {  // is AccessorDescriptor
1358             // may GC in NewAccessorData, so we need to handle getter and setter.
1359             JSThread *thread = op->GetThread();
1360             JSHandle<AccessorData> accessor = thread->GetEcmaVM()->GetFactory()->NewAccessorData();
1361             if (desc.HasGetter()) {
1362                 accessor->SetGetter(thread, desc.GetGetter());
1363             }
1364 
1365             if (desc.HasSetter()) {
1366                 accessor->SetSetter(thread, desc.GetSetter());
1367             }
1368             op->UpdateDetector();
1369             success = op->AddPropertyInHolder(JSHandle<JSTaggedValue>::Cast(accessor), attr);
1370         }
1371 
1372         return success;
1373     }
1374 
1375     // 3. Return true, if every field in Desc is absent
1376     // 4. Return true, if every field in Desc also occurs in current and the value of every field in Desc is the
1377     // same value as the corresponding field in current when compared using the SameValue algorithm.
1378     if ((!desc.HasEnumerable() || desc.IsEnumerable() == current.IsEnumerable()) &&
1379         (!desc.HasConfigurable() || desc.IsConfigurable() == current.IsConfigurable()) &&
1380         (!desc.HasValue() || JSTaggedValue::SameValue(current.GetValue(), desc.GetValue())) &&
1381         (!desc.HasWritable() || (current.IsWritable() == desc.IsWritable())) &&
1382         (!desc.HasGetter() ||
1383          (current.HasGetter() && JSTaggedValue::SameValue(current.GetGetter(), desc.GetGetter()))) &&
1384         (!desc.HasSetter() ||
1385          (current.HasSetter() && JSTaggedValue::SameValue(current.GetSetter(), desc.GetSetter())))) {
1386         return true;
1387     }
1388 
1389     // 5. If the [[Configurable]] field of current is false, then
1390     if (!current.IsConfigurable()) {
1391         // 5a. Return false, if the [[Configurable]] field of Desc is true.
1392         if (desc.HasConfigurable() && desc.IsConfigurable()) {
1393             return false;
1394         }
1395         // b. Return false, if the [[Enumerable]] field of Desc is present and the [[Enumerable]] fields of current
1396         // and Desc are the Boolean negation of each other.
1397         if (desc.HasEnumerable() && (desc.IsEnumerable() != current.IsEnumerable())) {
1398             return false;
1399         }
1400     }
1401 
1402     // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
1403     if (desc.IsGenericDescriptor()) {
1404         // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have different results, then
1405     } else if (current.IsDataDescriptor() != desc.IsDataDescriptor()) {
1406         // 7a. Return false, if the [[Configurable]] field of current is false.
1407         if (!current.IsConfigurable()) {
1408             return false;
1409         }
1410         // 7b. If IsDataDescriptor(current) is true, then
1411         if (current.IsDataDescriptor()) {
1412             // 7bi. If O is not undefined, convert the property named P of object O from a data property to an
1413             // accessor property. Preserve the existing values of the converted property’s [[Configurable]] and
1414             // [[Enumerable]] attributes and set the rest of the property’s attributes to their default values.
1415         } else {
1416             // 7ci.  If O is not undefined, convert the property named P of object O from an accessor property to a
1417             // data property. Preserve the existing values of the converted property’s [[Configurable]] and
1418             // [[Enumerable]] attributes and set the rest of the property’s attributes to their default values.
1419         }
1420         // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
1421     } else if (current.IsDataDescriptor() && desc.IsDataDescriptor()) {
1422         // 8a. If the [[Configurable]] field of current is false, then
1423         if (!current.IsConfigurable() && !ValidateDataDescriptorWhenConfigurable(op, desc, current, sCheckMode)) {
1424             return false;
1425         }
1426         // 8b. Else the [[Configurable]] field of current is true, so any change is acceptable.
1427     } else {  // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true,
1428         // 9a. If the [[Configurable]] field of current is false, then
1429         if (!current.IsConfigurable()) {
1430             // i. Return false, if the [[Set]] field of Desc is present and SameValue(Desc.[[Set]], current.[[Set]])
1431             // is false.
1432             if (desc.HasSetter() && !JSTaggedValue::SameValue(current.GetSetter(), desc.GetSetter())) {
1433                 return false;
1434             }
1435             // ii. Return false, if the [[Get]] field of Desc is present and SameValue(Desc.[[Get]],
1436             // current.[[Get]]) is false.
1437             if (desc.HasGetter() && !JSTaggedValue::SameValue(current.GetGetter(), desc.GetGetter())) {
1438                 return false;
1439             }
1440         }
1441     }
1442 
1443     if (op->HasHolder()) {
1444         // 10. If O is not undefined, then
1445         // a. For each field of Desc that is present, set the corresponding attribute of the property named P of object
1446         // O to the value of the field.
1447         if (!desc.HasValue() && desc.HasWritable() && current.HasValue()) {
1448             // [[Value]] and [[Writable]] attributes are set to the value of the corresponding field in Desc
1449             // if Desc has that field or to the attribute's default value otherwise.
1450             PropertyDescriptor newDesc = desc;
1451             JSHandle<JSTaggedValue> valueHandle = current.GetValue();
1452             if (valueHandle->IsPropertyBox()) {
1453                 JSTaggedValue value = PropertyBox::Cast(valueHandle->GetTaggedObject())->GetValue();
1454                 valueHandle = JSHandle<JSTaggedValue>(op->GetThread(), value);
1455             }
1456             newDesc.SetValue(valueHandle);
1457             op->UpdateDetector();
1458             return op->WriteDataPropertyInHolder(newDesc);
1459         }
1460         op->UpdateDetector();
1461         return op->WriteDataPropertyInHolder(desc);
1462     }
1463     return true;
1464 }
1465 
1466 // 9.1.6.2 IsCompatiblePropertyDescriptor (Extensible, Desc, Current)
IsCompatiblePropertyDescriptor(bool extensible,const PropertyDescriptor & desc,const PropertyDescriptor & current)1467 bool JSObject::IsCompatiblePropertyDescriptor(bool extensible, const PropertyDescriptor &desc,
1468                                               const PropertyDescriptor &current)
1469 {
1470     // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined, Extensible, Desc, Current).
1471     ObjectOperator op;
1472     return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current);
1473 }
1474 
GetPrototype(const JSHandle<JSObject> & obj)1475 JSTaggedValue JSObject::GetPrototype(const JSHandle<JSObject> &obj)
1476 {
1477     JSHClass *hclass = obj->GetJSHClass();
1478     return hclass->GetPrototype();
1479 }
1480 
SetPrototype(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & proto,bool isChangeProto)1481 bool JSObject::SetPrototype(JSThread *thread, const JSHandle<JSObject> &obj,
1482                             const JSHandle<JSTaggedValue> &proto,
1483                             bool isChangeProto)
1484 {
1485     ASSERT_PRINT(proto->IsECMAObject() || proto->IsNull(), "proto must be object or null");
1486     JSTaggedValue current = JSObject::GetPrototype(obj);
1487     if (current == proto.GetTaggedValue()) {
1488         return true;
1489     }
1490     if (!obj->IsExtensible()) {
1491         return false;
1492     }
1493     bool done = false;
1494     JSMutableHandle<JSTaggedValue> tempProtoHandle(thread, proto.GetTaggedValue());
1495     while (!done) {
1496         if (tempProtoHandle->IsNull() || !tempProtoHandle->IsECMAObject()) {
1497             done = true;
1498         } else if (JSTaggedValue::SameValue(tempProtoHandle.GetTaggedValue(), obj.GetTaggedValue())) {
1499             return false;
1500         } else {
1501             if (tempProtoHandle->IsJSProxy()) {
1502                 break;
1503             }
1504             tempProtoHandle.Update(JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(tempProtoHandle)));
1505             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1506         }
1507     }
1508     ElementsKind oldKind = obj->GetJSHClass()->GetElementsKind();
1509     // map transition
1510     JSHClass::SetPrototypeTransition(thread, obj, proto, isChangeProto);
1511     TryMigrateToGenericKindForJSObject(thread, obj, oldKind);
1512     return true;
1513 }
1514 
HasProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key)1515 bool JSObject::HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key)
1516 {
1517     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1518     JSHandle<JSTaggedValue> objValue(obj);
1519     ObjectOperator op(thread, objValue, key);
1520 
1521     JSHandle<JSTaggedValue> holder = op.GetHolder();
1522     if (holder->IsJSProxy()) {
1523         return JSProxy::HasProperty(thread, JSHandle<JSProxy>::Cast(holder), key);
1524     }
1525 
1526     return op.IsFound();
1527 }
1528 
HasProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index)1529 bool JSObject::HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index)
1530 {
1531     JSHandle<JSTaggedValue> objValue(obj);
1532     ObjectOperator op(thread, objValue, index);
1533 
1534     JSHandle<JSTaggedValue> holder = op.GetHolder();
1535     if (holder->IsJSProxy()) {
1536         JSHandle<JSTaggedValue> key(thread, JSTaggedValue(index));
1537         return JSProxy::HasProperty(thread, JSHandle<JSProxy>::Cast(holder), key);
1538     }
1539 
1540     return op.IsFound();
1541 }
1542 
PreventExtensions(JSThread * thread,const JSHandle<JSObject> & obj)1543 bool JSObject::PreventExtensions(JSThread *thread, const JSHandle<JSObject> &obj)
1544 {
1545     if (obj->IsExtensible()) {
1546         JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
1547         JSHandle<JSHClass> newHclass = JSHClass::TransitionExtension(thread, jshclass);
1548 #if ECMASCRIPT_ENABLE_IC
1549         JSHClass::NotifyHclassChanged(thread, jshclass, newHclass);
1550 #endif
1551         ElementsKind oldKind = obj->GetJSHClass()->GetElementsKind();
1552         JSHClass::RestoreElementsKindToGeneric(*newHclass);
1553         obj->SynchronizedSetClass(thread, *newHclass);
1554         TryMigrateToGenericKindForJSObject(thread, obj, oldKind);
1555     }
1556 
1557     return true;
1558 }
1559 
1560 // 9.1.12 [[OwnPropertyKeys]] ( )
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSObject> & obj)1561 JSHandle<TaggedArray> JSObject::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj)
1562 {
1563     uint32_t numOfElements = obj->GetNumberOfElements();
1564     uint32_t keyLen = numOfElements + obj->GetNumberOfKeys();
1565 
1566     JSHandle<TaggedArray> keyArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(keyLen);
1567 
1568     if (numOfElements > 0) {
1569         GetAllElementKeys(thread, obj, 0, keyArray);
1570     }
1571     GetAllKeys(thread, obj, static_cast<int32_t>(numOfElements), keyArray);
1572     return keyArray;
1573 }
1574 
GetAllPropertyKeys(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t filter)1575 JSHandle<TaggedArray> JSObject::GetAllPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t filter)
1576 {
1577     JSMutableHandle<JSObject> currentObj(thread, obj);
1578     JSMutableHandle<JSTaggedValue> currentObjValue(thread, currentObj);
1579 
1580     uint32_t curObjNumberOfElements = currentObj->GetNumberOfElements();
1581     uint32_t curObjNumberOfKeys = currentObj->GetNumberOfKeys();
1582     uint32_t curObjectKeysLength = curObjNumberOfElements + curObjNumberOfKeys;
1583     uint32_t retArrayLength = curObjectKeysLength;
1584     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1585     JSMutableHandle<TaggedArray> retArray(thread, factory->NewTaggedArray(retArrayLength));
1586     uint32_t retArrayEffectivelength = 0;
1587 
1588     do {
1589         curObjNumberOfElements = currentObj->GetNumberOfElements();
1590         curObjNumberOfKeys = currentObj->GetNumberOfKeys();
1591         curObjectKeysLength = curObjNumberOfElements + curObjNumberOfKeys;
1592         uint32_t minRequireLength = curObjectKeysLength + retArrayEffectivelength;
1593         if (retArrayLength < minRequireLength) {
1594             // expand retArray
1595             if (retArrayLength != 0) {
1596                 retArray.Update(factory->NewAndCopyTaggedArray(retArray, minRequireLength, retArrayLength));
1597             } else {
1598                 retArray.Update(factory->NewTaggedArray(minRequireLength));
1599             }
1600             retArrayLength = minRequireLength;
1601         }
1602 
1603         GetAllElementKeysByFilter(thread, currentObj, retArray, retArrayEffectivelength, filter);
1604 
1605         GetAllKeysByFilter(thread, currentObj, retArrayEffectivelength, retArray, filter);
1606         bool isInculdePrototypes = (filter & NATIVE_KEY_INCLUDE_PROTOTYPES);
1607         if (!isInculdePrototypes) {
1608             break;
1609         }
1610         currentObj.Update(GetPrototype(currentObj));
1611         currentObjValue.Update(currentObj);
1612     } while (currentObjValue->IsHeapObject());
1613 
1614     if (retArrayEffectivelength == 0 && (filter & NATIVE_KEY_OWN_ONLY)) {
1615         return retArray;
1616     }
1617     JSMutableHandle<JSTaggedValue> element(thread, JSTaggedValue::Undefined());
1618     if (filter & NATIVE_KEY_NUMBERS_TO_STRINGS) {
1619         for (uint32_t i = 0; i < retArrayEffectivelength; i++) {
1620             element.Update(retArray->Get(i));
1621             if (element->IsNumber()) {
1622                 retArray->Set(thread, i, base::NumberHelper::NumberToString(thread,
1623                     JSTaggedValue(element->GetNumber())));
1624             }
1625         }
1626     }
1627     uint32_t elementIndex = 0;
1628     if (filter & NATIVE_KEY_SKIP_STRINGS) {
1629         while ((retArrayEffectivelength > 0) && (elementIndex < retArrayEffectivelength)) {
1630             if (retArray->Get(elementIndex).IsString()) {
1631                 TaggedArray::RemoveElementByIndex(thread, retArray, elementIndex, retArrayEffectivelength);
1632                 retArrayEffectivelength--;
1633             } else {
1634                 elementIndex++;
1635             }
1636         }
1637     }
1638     if (retArray->GetLength() > retArrayEffectivelength) {
1639         retArray->Trim(thread, retArrayEffectivelength);
1640     }
1641     return retArray;
1642 }
1643 
CollectEnumKeysAlongProtoChain(JSThread * thread,const JSHandle<JSObject> & obj,JSHandle<TaggedArray> keyArray,uint32_t * keys,JSHandle<TaggedQueue> shadowQueue,int32_t lastLength)1644 void JSObject::CollectEnumKeysAlongProtoChain(JSThread *thread, const JSHandle<JSObject> &obj,
1645                                               JSHandle<TaggedArray> keyArray, uint32_t *keys,
1646                                               JSHandle<TaggedQueue> shadowQueue, int32_t lastLength)
1647 {
1648     ASSERT(!obj->IsJSGlobalObject());
1649 
1650     TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
1651     if (!array->IsDictionaryMode()) {
1652         JSHClass *jsHclass = obj->GetJSHClass();
1653         int end = static_cast<int>(jsHclass->NumberOfProps());
1654         if (end > 0) {
1655             LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject())
1656                 ->GetAllEnumKeys(thread, end, *keys, keyArray, keys, shadowQueue, obj, lastLength);
1657         }
1658         return;
1659     }
1660     NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
1661     dict->GetAllEnumKeys(thread, *keys, keyArray, keys, shadowQueue, lastLength);
1662 }
1663 
AppendOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSObject> & obj,JSHandle<TaggedArray> keyArray,uint32_t * keys,JSHandle<TaggedQueue> shadowQueue)1664 void JSObject::AppendOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj,
1665                                          JSHandle<TaggedArray> keyArray, uint32_t *keys,
1666                                          JSHandle<TaggedQueue> shadowQueue)
1667 {
1668     int32_t lastLength = *keys;
1669     uint32_t numOfElements = obj->GetNumberOfElements();
1670     if (numOfElements > 0) {
1671         CollectEnumElementsAlongProtoChain(thread, obj, *keys, keyArray, keys, lastLength);
1672     }
1673     CollectEnumKeysAlongProtoChain(thread, obj, keyArray, keys, shadowQueue, lastLength);
1674 }
1675 
GetOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSObject> & obj)1676 JSHandle<TaggedArray> JSObject::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj)
1677 {
1678     uint32_t numOfElements = obj->GetNumberOfElements();
1679     uint32_t keyLen = numOfElements + obj->GetNumberOfKeys();
1680 
1681     JSHandle<TaggedArray> keyArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(keyLen);
1682 
1683     if (numOfElements > 0) {
1684         GetEnumElementKeys(thread, obj, 0, keyArray);
1685     }
1686     GetAllEnumKeys(thread, obj, static_cast<int32_t>(numOfElements), keyArray);
1687     return keyArray;
1688 }
1689 
ObjectCreate(JSThread * thread,const JSHandle<JSObject> & proto)1690 JSHandle<JSObject> JSObject::ObjectCreate(JSThread *thread, const JSHandle<JSObject> &proto)
1691 {
1692     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1693     JSHandle<JSFunction> constructor(env->GetObjectFunction());
1694     JSHandle<JSObject> objHandle = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(constructor);
1695     SetPrototype(thread, objHandle, JSHandle<JSTaggedValue>(proto));
1696     return objHandle;
1697 }
1698 
1699 // 7.3.4 CreateDataProperty (O, P, V)
CreateDataProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,SCheckMode sCheckMode)1700 bool JSObject::CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1701                                   const JSHandle<JSTaggedValue> &value, SCheckMode sCheckMode)
1702 {
1703     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1704     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1705     if (!JSHandle<JSTaggedValue>::Cast(obj)->IsJSShared()) {
1706         sCheckMode = SCheckMode::CHECK;
1707     }
1708     auto result = ObjectFastOperator::SetPropertyByValue<ObjectFastOperator::Status::DefineSemantics>(
1709         thread, obj.GetTaggedValue(), key.GetTaggedValue(), value.GetTaggedValue(), sCheckMode);
1710     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1711     if (!result.IsHole()) {
1712         return !result.IsException();
1713     }
1714     PropertyDescriptor desc(thread, value, true, true, true);
1715     return JSTaggedValue::DefineOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key, desc, sCheckMode);
1716 }
1717 
CreateDataProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const JSHandle<JSTaggedValue> & value,SCheckMode sCheckMode)1718 bool JSObject::CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1719                                   const JSHandle<JSTaggedValue> &value, SCheckMode sCheckMode)
1720 {
1721     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1722     auto result = ObjectFastOperator::SetPropertyByIndex<ObjectFastOperator::Status::DefineSemantics>
1723             (thread, obj.GetTaggedValue(), index, value.GetTaggedValue());
1724     if (!result.IsHole()) {
1725         return !result.IsException();
1726     }
1727     PropertyDescriptor desc(thread, value, true, true, true);
1728     return DefineOwnProperty(thread, obj, index, desc, sCheckMode);
1729 }
1730 
1731 // 7.3.5 CreateMethodProperty (O, P, V)
CreateDataPropertyOrThrow(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,SCheckMode sCheckMode)1732 bool JSObject::CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj,
1733                                          const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
1734                                          SCheckMode sCheckMode)
1735 {
1736     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1737     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1738 
1739     bool success = CreateDataProperty(thread, obj, key, value, sCheckMode);
1740     if (!success) {
1741         THROW_TYPE_ERROR_AND_RETURN(thread, "failed to create data property", success);
1742     }
1743     return success;
1744 }
1745 
CreateDataPropertyOrThrow(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const JSHandle<JSTaggedValue> & value,SCheckMode sCheckMode)1746 bool JSObject::CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1747                                          const JSHandle<JSTaggedValue> &value,  SCheckMode sCheckMode)
1748 {
1749     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1750 
1751     bool success = CreateDataProperty(thread, obj, index, value, sCheckMode);
1752     if (!success) {
1753         THROW_TYPE_ERROR_AND_RETURN(thread, "failed to create data property", success);
1754     }
1755     return success;
1756 }
1757 // 7.3.6 CreateDataPropertyOrThrow (O, P, V)
CreateMethodProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1758 bool JSObject::CreateMethodProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1759                                     const JSHandle<JSTaggedValue> &value)
1760 {
1761     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1762     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1763 
1764     PropertyDescriptor desc(thread, value, true, false, true);
1765     return DefineOwnProperty(thread, obj, key, desc);
1766 }
1767 
CallFunction(JSThread * thread,const JSHandle<JSTaggedValue> & func)1768 JSHandle<JSTaggedValue> JSObject::CallFunction(JSThread *thread, const JSHandle<JSTaggedValue> &func)
1769 {
1770     if (func->IsUndefined() || func->IsNull()) {
1771         return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
1772     }
1773     if (!func->IsCallable()) {
1774         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not Callable", func);
1775     }
1776     return func;
1777 }
1778 
1779 // 7.3.9 GetMethod (O, P)
GetMethod(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1780 JSHandle<JSTaggedValue> JSObject::GetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1781                                             const JSHandle<JSTaggedValue> &key)
1782 {
1783     JSHandle<JSTaggedValue> func = JSTaggedValue::GetProperty(thread, obj, key).GetValue();
1784     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1785     func = CallFunction(thread, func);
1786     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1787     return func;
1788 }
1789 
FastGetMethod(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1790 JSHandle<JSTaggedValue> JSObject::FastGetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1791                                                 const JSHandle<JSTaggedValue> &key)
1792 {
1793     JSHandle<JSTaggedValue> func(thread, ObjectFastOperator::FastGetPropertyByName(thread, obj.GetTaggedValue(),
1794                                                                                    key.GetTaggedValue()));
1795     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1796     func = CallFunction(thread, func);
1797     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1798     return func;
1799 }
1800 
1801 // 7.3.14 SetIntegrityLevel (O, level)
SetIntegrityLevel(JSThread * thread,const JSHandle<JSObject> & obj,IntegrityLevel level)1802 bool JSObject::SetIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level)
1803 {
1804     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1805     ASSERT_PRINT((level == IntegrityLevel::SEALED || level == IntegrityLevel::FROZEN),
1806                  "level is not a valid IntegrityLevel");
1807 
1808     bool status = JSTaggedValue::PreventExtensions(thread, JSHandle<JSTaggedValue>(obj));
1809     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1810     if (!status) {
1811         return false;
1812     }
1813 
1814     JSHandle<TaggedArray> jshandleKeys =
1815         JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>(obj));
1816     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1817     PropertyDescriptor descNoConf(thread);
1818     descNoConf.SetConfigurable(false);
1819     PropertyDescriptor descNoConfWrite(thread);
1820     descNoConfWrite.SetWritable(false);
1821     descNoConfWrite.SetConfigurable(false);
1822 
1823     if (level == IntegrityLevel::SEALED) {
1824         uint32_t length = jshandleKeys->GetLength();
1825         if (length == 0) {
1826             return true;
1827         }
1828         auto key = jshandleKeys->Get(0);
1829         JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1830         for (uint32_t i = 0; i < length; i++) {
1831             auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1832             handleKey.Update(taggedKey);
1833             [[maybe_unused]] bool success =
1834                 JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(obj), handleKey, descNoConf);
1835             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1836         }
1837     } else {
1838         uint32_t length = jshandleKeys->GetLength();
1839         if (length == 0) {
1840             return true;
1841         }
1842         auto key = jshandleKeys->Get(0);
1843         JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1844         for (uint32_t i = 0; i < length; i++) {
1845             auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1846             handleKey.Update(taggedKey);
1847             PropertyDescriptor currentDesc(thread);
1848             bool curDescStatus =
1849                 JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), handleKey, currentDesc);
1850             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1851             if (curDescStatus) {
1852                 PropertyDescriptor desc = currentDesc.IsAccessorDescriptor() ? descNoConf : descNoConfWrite;
1853                 [[maybe_unused]] bool success =
1854                     JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(obj), handleKey, desc);
1855                 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1856             }
1857         }
1858     }
1859     return true;
1860 }
1861 
FreezeSharedObject(JSThread * thread,const JSHandle<JSObject> & obj)1862 bool JSObject::FreezeSharedObject(JSThread *thread, const JSHandle<JSObject> &obj)
1863 {
1864     ASSERT_PRINT(JSHandle<JSTaggedValue>(obj)->IsJSSharedObject() ||
1865                  JSHandle<JSTaggedValue>(obj)->IsJSSharedFunction() ||
1866                  JSHandle<JSTaggedValue>(obj)->IsJSSharedAsyncFunction(),
1867                  "Obj is not a valid shared object");
1868     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1869     // It is not extensible for shared object.
1870     if (obj->IsExtensible()) {
1871         return false;
1872     }
1873     JSHandle<JSHClass> hclass(thread, obj->GetClass());
1874     auto newClass = JSHClass::Clone(thread, hclass);
1875     if (!hclass->IsDictionaryMode()) {
1876         uint32_t propNumber = hclass->NumberOfProps();
1877         JSHandle<LayoutInfo> layoutInfo(thread, hclass->GetLayout());
1878         JSHandle<LayoutInfo> newLayoutInfo = factory->CreateSLayoutInfo(propNumber);
1879         for (uint32_t i = 0; i < propNumber; i++) {
1880             JSTaggedValue key = layoutInfo->GetKey(i);
1881             PropertyAttributes attr = layoutInfo->GetAttr(i);
1882             attr.SetWritable(false);
1883             newLayoutInfo->AddKey(thread, i, key, attr);
1884         }
1885         newClass->SetLayout(thread, newLayoutInfo);
1886         obj->SynchronizedSetClass(thread, *newClass);
1887     } else {
1888         auto dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
1889         dict->UpdateAllAttributesToNoWitable(thread);
1890     }
1891     return true;
1892 }
1893 
1894 // 7.3.15 TestIntegrityLevel (O, level)
TestIntegrityLevel(JSThread * thread,const JSHandle<JSObject> & obj,IntegrityLevel level)1895 bool JSObject::TestIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level)
1896 {
1897     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1898     ASSERT_PRINT((level == IntegrityLevel::SEALED || level == IntegrityLevel::FROZEN),
1899                  "level is not a valid IntegrityLevel");
1900 
1901     bool status = JSHandle<JSTaggedValue>(obj)->IsExtensible(thread);
1902     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1903     if (status) {
1904         return false;
1905     }
1906 
1907     JSHandle<TaggedArray> jshandleKeys =
1908         JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>(obj));
1909     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1910     uint32_t length = jshandleKeys->GetLength();
1911     if (length == 0) {
1912         return true;
1913     }
1914     auto key = jshandleKeys->Get(0);
1915     JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1916     for (uint32_t i = 0; i < length; i++) {
1917         auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1918         handleKey.Update(taggedKey);
1919         PropertyDescriptor currentDesc(thread);
1920         bool curDescStatus =
1921             JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), handleKey, currentDesc);
1922         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1923         if (curDescStatus) {
1924             if (currentDesc.IsConfigurable()) {
1925                 return false;
1926             }
1927             if (level == IntegrityLevel::FROZEN &&
1928                 currentDesc.IsDataDescriptor() && currentDesc.IsWritable()) {
1929                 return false;
1930             }
1931         }
1932     }
1933     return true;
1934 }
1935 
1936 // 7.3.21 EnumerableOwnNames (O)
EnumerableOwnNames(JSThread * thread,const JSHandle<JSObject> & obj)1937 JSHandle<TaggedArray> JSObject::EnumerableOwnNames(JSThread *thread, const JSHandle<JSObject> &obj)
1938 {
1939     ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
1940     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1941     JSHandle<JSTaggedValue> tagObj(obj);
1942     // fast mode
1943     if (tagObj->IsJSObject() && !tagObj->IsTypedArray() && !tagObj->IsModuleNamespace()) {
1944         uint32_t copyLengthOfKeys = 0;
1945         uint32_t copyLengthOfElements = 0;
1946         auto keyElementPair = GetOwnEnumerableNamesInFastMode(thread, obj, &copyLengthOfKeys, &copyLengthOfElements);
1947         JSHandle<TaggedArray> keyArray = keyElementPair.first;
1948         JSHandle<TaggedArray> elementArray = keyElementPair.second;
1949         JSHandle<TaggedArray> keys;
1950         if (copyLengthOfKeys != 0 && copyLengthOfElements != 0) {
1951             keys = TaggedArray::AppendSkipHole(thread, elementArray, keyArray, copyLengthOfKeys + copyLengthOfElements);
1952         } else if (copyLengthOfKeys != 0) {
1953             if (copyLengthOfKeys < keyArray->GetLength()) {
1954                 // keyArray will skip nonEnumerable properties, need re-set length.
1955                 keyArray->Trim(thread, copyLengthOfKeys);
1956             }
1957             return keyArray;
1958         } else if (copyLengthOfElements != 0) {
1959             if (copyLengthOfElements < elementArray->GetLength()) {
1960                 // elementArray will skip hole value, need re-set length.
1961                 elementArray->Trim(thread, copyLengthOfElements);
1962             }
1963             return elementArray;
1964         } else {
1965             keys = factory->EmptyArray();
1966         }
1967         return keys;
1968     }
1969 
1970     uint32_t copyLength = 0;
1971     JSHandle<TaggedArray> keys = JSTaggedValue::GetOwnPropertyKeys(thread, tagObj);
1972     RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1973     uint32_t length = keys->GetLength();
1974 
1975     JSHandle<TaggedArray> names = factory->NewTaggedArray(length);
1976     JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
1977     for (uint32_t i = 0; i < length; i++) {
1978         keyHandle.Update(keys->Get(i));
1979         if (keyHandle->IsString()) {
1980             PropertyDescriptor desc(thread);
1981             bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj),
1982                                                         keyHandle, desc);
1983             RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1984 
1985             if (status && desc.IsEnumerable()) {
1986                 names->Set(thread, copyLength, keyHandle);
1987                 copyLength++;
1988             }
1989         }
1990     }
1991 
1992     return factory->CopyArray(names, length, copyLength);
1993 }
1994 
EnumerableOwnPropertyNamesHelper(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<TaggedArray> & arr,JSHandle<TaggedArray> & prop,uint32_t & index,bool & fastMode,PropertyKind kind)1995 void JSObject::EnumerableOwnPropertyNamesHelper(JSThread *thread, const JSHandle<JSObject> &obj,
1996     const JSHandle<TaggedArray> &arr, JSHandle<TaggedArray> &prop, uint32_t &index, bool &fastMode, PropertyKind kind)
1997 {
1998     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1999     JSHandle<JSHClass> objClass(thread, obj->GetJSHClass());
2000     uint32_t length = arr->GetLength();
2001     for (uint32_t i = 0; i < length; i++) {
2002         key.Update(arr->Get(thread, i));
2003         if (!JSTaggedValue::IsPropertyKey(key)) {
2004             break;
2005         }
2006         JSTaggedValue value = JSTaggedValue::Hole();
2007         if (fastMode) {
2008             value = ObjectFastOperator::GetPropertyByValue<ObjectFastOperator::Status::UseOwn>
2009                     (thread, obj.GetTaggedValue(), key.GetTaggedValue());
2010             RETURN_IF_ABRUPT_COMPLETION(thread);
2011         }
2012         if (value.IsHole()) {
2013             PropertyDescriptor desc(thread);
2014             bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), key, desc);
2015             RETURN_IF_ABRUPT_COMPLETION(thread);
2016             if (!status || !desc.IsEnumerable()) {
2017                 continue;
2018             }
2019             if (desc.HasValue()) {
2020                 value = desc.GetValue().GetTaggedValue();
2021             } else {
2022                 OperationResult opResult = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key);
2023                 RETURN_IF_ABRUPT_COMPLETION(thread);
2024                 value = opResult.GetValue().GetTaggedValue();
2025             }
2026         }
2027         index = SetValuesOrEntries(thread, prop, index, key, JSHandle<JSTaggedValue>(thread, value), kind);
2028         fastMode = fastMode ? CheckHClassHit(obj, objClass) : fastMode;
2029     }
2030 }
2031 
EnumerableOwnPropertyNames(JSThread * thread,const JSHandle<JSObject> & obj,PropertyKind kind)2032 JSHandle<TaggedArray> JSObject::EnumerableOwnPropertyNames(JSThread *thread, const JSHandle<JSObject> &obj,
2033                                                            PropertyKind kind)
2034 {
2035     // 1. Assert: Type(O) is Object.
2036     ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
2037 
2038     // 2. Let ownKeys be ? O.[[OwnPropertyKeys]]().
2039     JSHandle<JSTaggedValue> tagObj(obj);
2040     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2041     if (tagObj->IsJSObject() && !tagObj->IsJSProxy() && !tagObj->IsTypedArray() && !tagObj->IsModuleNamespace()) {
2042         uint32_t copyLengthOfKeys = 0;
2043         uint32_t copyLengthOfElements = 0;
2044         uint32_t index = 0;
2045         bool fastMode = true;
2046         auto keyElementPair = GetOwnEnumerableNamesInFastMode(thread, obj, &copyLengthOfKeys, &copyLengthOfElements);
2047         JSHandle<TaggedArray> keyArray = keyElementPair.first;
2048         JSHandle<TaggedArray> elementArray = keyElementPair.second;
2049         JSHandle<TaggedArray> properties = factory->NewTaggedArray(copyLengthOfKeys + copyLengthOfElements);
2050         if (copyLengthOfElements != 0) {
2051             EnumerableOwnPropertyNamesHelper(thread, obj, elementArray, properties, index, fastMode, kind);
2052         }
2053         if (copyLengthOfKeys != 0) {
2054             EnumerableOwnPropertyNamesHelper(thread, obj, keyArray, properties, index, fastMode, kind);
2055         }
2056         if (UNLIKELY(!fastMode && index < copyLengthOfKeys + copyLengthOfElements)) {
2057             properties->Trim(thread, index);
2058         }
2059         return properties;
2060     }
2061 
2062     JSHandle<TaggedArray> ownKeys = JSTaggedValue::GetOwnPropertyKeys(thread, tagObj);
2063     RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
2064 
2065     // 3. Let properties be a new empty List.
2066     uint32_t length = ownKeys->GetLength();
2067     JSHandle<TaggedArray> properties = factory->NewTaggedArray(length);
2068 
2069     // 4. For each element key of ownKeys, do
2070     // a. If Type(key) is String, then
2071     //     i. Let desc be ? O.[[GetOwnProperty]](key).
2072     //     ii. If desc is not undefined and desc.[[Enumerable]] is true, then
2073     //         1. If kind is key, append key to properties.
2074     //         2. Else,
2075     //            a. Let value be ? Get(O, key).
2076     //            b. If kind is value, append value to properties.
2077     //            c. Else,
2078     //               i. Assert: kind is key+value.
2079     //               ii. Let entry be ! CreateArrayFromList(« key, value »).
2080     //               iii. Append entry to properties.
2081     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2082     uint32_t index = 0;
2083     for (uint32_t i = 0; i < length; i++) {
2084         key.Update(ownKeys->Get(thread, i));
2085         if (key->IsString()) {
2086             PropertyDescriptor desc(thread);
2087             bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj),
2088                                                         key, desc);
2089             RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
2090             if (status && desc.IsEnumerable()) {
2091                 if (kind == PropertyKind::KEY) {
2092                     properties->Set(thread, index++, key);
2093                 } else {
2094                     OperationResult result =
2095                         JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key);
2096                     RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
2097                     JSHandle<JSTaggedValue> value = result.GetValue();
2098                     index = SetValuesOrEntries(thread, properties, index, key, value, kind);
2099                 }
2100             }
2101         }
2102     }
2103 
2104     if (UNLIKELY(index < length)) {
2105         properties->Trim(thread, index);
2106     }
2107     // 5. Return properties.
2108     return properties;
2109 }
2110 
GetFunctionRealm(JSThread * thread,const JSHandle<JSTaggedValue> & object)2111 JSHandle<GlobalEnv> JSObject::GetFunctionRealm(JSThread *thread, const JSHandle<JSTaggedValue> &object)
2112 {
2113     // 1. Assert: obj is a callable object.
2114     ASSERT(object->IsCallable());
2115     // 2. If obj has a [[Realm]] internal slot, then return obj’s [[Realm]] internal slot.
2116     // 3. If obj is a Bound Function exotic object, then
2117     if (object->IsBoundFunction()) {
2118         // a. Let target be obj’s [[BoundTargetFunction]] internal slot.
2119         JSHandle<JSTaggedValue> target(thread, JSHandle<JSBoundFunction>(object)->GetBoundTarget());
2120         // b. Return GetFunctionRealm(target).
2121         return GetFunctionRealm(thread, target);
2122     }
2123     // 4. If obj is a Proxy exotic object, then
2124     if (object->IsJSProxy()) {
2125         // a. If the value of the [[ProxyHandler]] internal slot of obj is null, throw a TypeError exception.
2126         if (JSHandle<JSProxy>(object)->GetHandler().IsNull()) {
2127             THROW_TYPE_ERROR_AND_RETURN(thread, "JSObject::GetFunctionRealm: handler is null",
2128                                         JSHandle<GlobalEnv>(thread, JSTaggedValue::Exception()));
2129         }
2130         // b. Let proxyTarget be the value of obj’s [[ProxyTarget]] internal slot.
2131         JSHandle<JSTaggedValue> proxyTarget(thread, JSHandle<JSProxy>(object)->GetTarget());
2132         return GetFunctionRealm(thread, proxyTarget);
2133     }
2134 
2135     if (object->IsJSShared()) {
2136         // LexicalEnv in sharedConstructor is constructor itself. And Shared Constructors shares the same GlobalEnv.
2137         return thread->GetEcmaVM()->GetGlobalEnv();
2138     }
2139 
2140     JSTaggedValue maybeGlobalEnv = JSHandle<JSFunction>(object)->GetLexicalEnv();
2141     while (!maybeGlobalEnv.IsJSGlobalEnv()) {
2142         if (maybeGlobalEnv.IsUndefined()) {
2143             return thread->GetEcmaVM()->GetGlobalEnv();
2144         }
2145         maybeGlobalEnv = LexicalEnv::Cast(maybeGlobalEnv.GetTaggedObject())->GetParentEnv();
2146     }
2147     return JSHandle<GlobalEnv>(thread, maybeGlobalEnv);
2148 }
2149 
InstanceOf(JSThread * thread,const JSHandle<JSTaggedValue> & object,const JSHandle<JSTaggedValue> & target)2150 bool JSObject::InstanceOf(JSThread *thread, const JSHandle<JSTaggedValue> &object,
2151                           const JSHandle<JSTaggedValue> &target)
2152 {
2153     // 1. If Type(target) is not Object, throw a TypeError exception.
2154     if (!target->IsECMAObject()) {
2155         THROW_TYPE_ERROR_AND_RETURN(thread, "InstanceOf error when type of target is not Object", false);
2156     }
2157 
2158     EcmaVM *vm = thread->GetEcmaVM();
2159     // 2. Let instOfHandler be GetMethod(target, @@hasInstance).
2160     JSHandle<JSTaggedValue> instOfHandler = FastGetMethod(thread, target, vm->GetGlobalEnv()->GetHasInstanceSymbol());
2161 
2162     // 3. ReturnIfAbrupt(instOfHandler).
2163     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
2164 
2165     // 4. If instOfHandler is not undefined, then
2166     if (!instOfHandler->IsUndefined()) {
2167         // a. Return ! ToBoolean(? Call(instOfHandler, target, «object»)).
2168         JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2169         EcmaRuntimeCallInfo *info =
2170             EcmaInterpreter::NewRuntimeCallInfo(thread, instOfHandler, target, undefined, 1);
2171         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
2172         info->SetCallArg(object.GetTaggedValue());
2173         JSTaggedValue tagged = JSFunction::Call(info);
2174         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
2175         return tagged.ToBoolean();
2176     }
2177 
2178     // 5. If IsCallable(target) is false, throw a TypeError exception.
2179     if (!target->IsCallable()) {
2180         THROW_TYPE_ERROR_AND_RETURN(thread, "InstanceOf error when target is not Callable", false);
2181     }
2182 
2183     // 6. Return ? OrdinaryHasInstance(target, object).
2184     return JSFunction::OrdinaryHasInstance(thread, target, object);
2185 }
2186 
2187 // ecma6.0 6.2.4.4
FromPropertyDescriptor(JSThread * thread,const PropertyDescriptor & desc)2188 JSHandle<JSTaggedValue> JSObject::FromPropertyDescriptor(JSThread *thread, const PropertyDescriptor &desc)
2189 {
2190     // 1. If Desc is undefined, return undefined
2191     if (desc.IsEmpty()) {
2192         return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
2193     }
2194 
2195     // 2. Let obj be ObjectCreate(%ObjectPrototype%).
2196     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
2197     JSHandle<JSFunction> objFunc(env->GetObjectFunction());
2198     JSHandle<JSObject> objHandle = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(objFunc);
2199 
2200     auto globalConst = thread->GlobalConstants();
2201     // 4. If Desc has a [[Value]] field, then Perform CreateDataProperty(obj, "value", Desc.[[Value]]).
2202     if (desc.HasValue()) {
2203         JSHandle<JSTaggedValue> valueStr = globalConst->GetHandledValueString();
2204         bool success = CreateDataProperty(thread, objHandle, valueStr, desc.GetValue());
2205         RASSERT_PRINT(success, "CreateDataProperty must be success");
2206     }
2207     // 5. If Desc has a [[Writable]] field, then Perform CreateDataProperty(obj, "writable", Desc.[[Writable]]).
2208     if (desc.HasWritable()) {
2209         JSHandle<JSTaggedValue> writableStr = globalConst->GetHandledWritableString();
2210         JSHandle<JSTaggedValue> writable(thread, JSTaggedValue(desc.IsWritable()));
2211         [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, writableStr, writable);
2212         ASSERT_PRINT(success, "CreateDataProperty must be success");
2213     }
2214     // 6. If Desc has a [[Get]] field, then Perform CreateDataProperty(obj, "get", Desc.[[Get]]).
2215     if (desc.HasGetter()) {
2216         JSHandle<JSTaggedValue> getStr = globalConst->GetHandledGetString();
2217         bool success = CreateDataProperty(thread, objHandle, getStr, desc.GetGetter());
2218         RASSERT_PRINT(success, "CreateDataProperty must be success");
2219     }
2220     // 7. If Desc has a [[Set]] field, then Perform CreateDataProperty(obj, "set", Desc.[[Set]])
2221     if (desc.HasSetter()) {
2222         JSHandle<JSTaggedValue> setStr = globalConst->GetHandledSetString();
2223         bool success = CreateDataProperty(thread, objHandle, setStr, desc.GetSetter());
2224         RASSERT_PRINT(success, "CreateDataProperty must be success");
2225     }
2226     // 8. If Desc has an [[Enumerable]] field, then Perform CreateDataProperty(obj, "enumerable",
2227     // Desc.[[Enumerable]]).
2228     if (desc.HasEnumerable()) {
2229         JSHandle<JSTaggedValue> enumerableStr = globalConst->GetHandledEnumerableString();
2230         JSHandle<JSTaggedValue> enumerable(thread, JSTaggedValue(desc.IsEnumerable()));
2231         [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, enumerableStr, enumerable);
2232         ASSERT_PRINT(success, "CreateDataProperty must be success");
2233     }
2234     // 9. If Desc has a [[Configurable]] field, then Perform CreateDataProperty(obj , "configurable",
2235     // Desc.[[Configurable]]).
2236     if (desc.HasConfigurable()) {
2237         JSHandle<JSTaggedValue> configurableStr = globalConst->GetHandledConfigurableString();
2238         JSHandle<JSTaggedValue> configurable(thread, JSTaggedValue(desc.IsConfigurable()));
2239         [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, configurableStr, configurable);
2240         ASSERT_PRINT(success, "CreateDataProperty must be success");
2241     }
2242     return JSHandle<JSTaggedValue>(objHandle);
2243 }
2244 
ToPropertyDescriptorFast(JSThread * thread,const JSHandle<JSTaggedValue> & obj,PropertyDescriptor & desc)2245 bool JSObject::ToPropertyDescriptorFast(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc)
2246 {
2247     auto *hclass = obj->GetTaggedObject()->GetClass();
2248     JSType jsType = hclass->GetObjectType();
2249     if (jsType != JSType::JS_OBJECT) {
2250         return false;
2251     }
2252     if (hclass->IsDictionaryMode()) {
2253         return false;
2254     }
2255     auto env = thread->GetEcmaVM()->GetGlobalEnv();
2256     auto globalConst = thread->GlobalConstants();
2257     if (hclass->GetPrototype() != env->GetObjectFunctionPrototype().GetTaggedValue()) {
2258         return false;
2259     }
2260     if (JSObject::Cast(hclass->GetPrototype().GetTaggedObject())->GetClass() !=
2261         env->GetObjectFunctionPrototypeClass().GetObject<JSHClass>()) {
2262         return false;
2263     }
2264     LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
2265     uint32_t propsNumber = hclass->NumberOfProps();
2266     for (uint32_t i = 0; i < propsNumber; i++) {
2267         auto attr = layoutInfo->GetAttr(i);
2268         if (attr.IsAccessor()) {
2269             return false;
2270         }
2271         auto key = layoutInfo->GetKey(i);
2272         auto value = JSObject::Cast(obj->GetTaggedObject())->GetProperty(hclass, attr);
2273         if (key == globalConst->GetEnumerableString()) {
2274             bool enumerable = value.ToBoolean();
2275             desc.SetEnumerable(enumerable);
2276         } else if (key == globalConst->GetConfigurableString()) {
2277             bool configurable = value.ToBoolean();
2278             desc.SetConfigurable(configurable);
2279         } else if (key == globalConst->GetValueString()) {
2280             auto handleValue = JSHandle<JSTaggedValue>(thread, value);
2281             desc.SetValue(handleValue);
2282         } else if (key == globalConst->GetWritableString()) {
2283             bool writable = value.ToBoolean();
2284             desc.SetWritable(writable);
2285         } else if (key == globalConst->GetGetString()) {
2286             if (!value.IsCallable()) {
2287                 return false;
2288             }
2289             auto getter = JSHandle<JSTaggedValue>(thread, value);
2290             desc.SetGetter(getter);
2291         } else if (key == globalConst->GetSetString()) {
2292             if (!value.IsCallable()) {
2293                 return false;
2294             }
2295             auto setter = JSHandle<JSTaggedValue>(thread, value);
2296             desc.SetSetter(setter);
2297         }
2298     }
2299 
2300     if (desc.IsAccessorDescriptor()) {
2301         // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, throw a TypeError exception.
2302         if (desc.HasValue() || desc.HasWritable()) {
2303             THROW_TYPE_ERROR_AND_RETURN(thread, "either Value or Writable is present", true);
2304         }
2305     }
2306     return true;
2307 }
2308 
2309 // ecma6.0 6.2.4.5 ToPropertyDescriptor ( Obj )
ToPropertyDescriptor(JSThread * thread,const JSHandle<JSTaggedValue> & obj,PropertyDescriptor & desc)2310 void JSObject::ToPropertyDescriptor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc)
2311 {
2312     if (!obj->IsECMAObject()) {
2313         // 2. If Type(Obj) is not Object, throw a TypeError exception.
2314         THROW_TYPE_ERROR(thread, "ToPropertyDescriptor error obj is not Object");
2315     }
2316 
2317     if (ToPropertyDescriptorFast(thread, obj, desc)) {
2318         return;
2319     }
2320     auto globalConst = thread->GlobalConstants();
2321     // 3. Let desc be a new Property Descriptor that initially has no fields.
2322     // 4. Let hasEnumerable be HasProperty(Obj, "enumerable")
2323     {
2324         ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetEnumerableString());
2325         if (op.IsFound()) {
2326             auto value = op.FastGetValue();
2327             bool enumerable = value->IsException() ? false : value->ToBoolean();
2328             desc.SetEnumerable(enumerable);
2329         }
2330     }
2331     // 7. Let hasConfigurable be HasProperty(Obj, "configurable").
2332     {
2333         ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetConfigurableString());
2334         if (op.IsFound()) {
2335             auto value = op.FastGetValue();
2336             bool conf = value->IsException() ? false : value->ToBoolean();
2337             desc.SetConfigurable(conf);
2338         }
2339     }
2340     // 10. Let hasValue be HasProperty(Obj, "value").
2341     {
2342         ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetValueString());
2343         if (op.IsFound()) {
2344             JSHandle<JSTaggedValue> prop = op.FastGetValue();
2345             desc.SetValue(prop);
2346         }
2347     }
2348     // 13. Let hasWritable be HasProperty(Obj, "writable").
2349     {
2350         ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetWritableString());
2351         if (op.IsFound()) {
2352             auto value = op.FastGetValue();
2353             bool writable = value->IsException() ? false : value->ToBoolean();
2354             desc.SetWritable(writable);
2355         }
2356     }
2357     // 16. Let hasGet be HasProperty(Obj, "get").
2358     {
2359         ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetGetString());
2360         if (op.IsFound()) {
2361             JSHandle<JSTaggedValue> getter = op.FastGetValue();
2362             if (!getter->IsCallable() && !getter->IsUndefined()) {
2363                 THROW_TYPE_ERROR(thread, "getter not callable or undefined");
2364             }
2365             desc.SetGetter(getter);
2366         }
2367     }
2368 
2369     // 19. Let hasSet be HasProperty(Obj, "set").
2370     {
2371         ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetSetString());
2372         if (op.IsFound()) {
2373             JSHandle<JSTaggedValue> setter = op.FastGetValue();
2374             if (!setter->IsCallable() && !setter->IsUndefined()) {
2375                 THROW_TYPE_ERROR(thread, "setter not callable or undefined");
2376             }
2377             desc.SetSetter(setter);
2378         }
2379     }
2380 
2381     // 22. If either desc.[[Get]] or desc.[[Set]] is present, then
2382     if (desc.IsAccessorDescriptor()) {
2383         // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, throw a TypeError exception.
2384         if (desc.HasValue() || desc.HasWritable()) {
2385             THROW_TYPE_ERROR(thread, "either desc.[[Value]] or desc.[[Writable]] is present");
2386         }
2387     }
2388     // 23. Return desc.
2389 }
2390 
ExtractConstructorAndRecordName(JSThread * thread,TaggedObject * obj,bool noAllocate,bool * isCallGetter)2391 const CString JSObject::ExtractConstructorAndRecordName(JSThread *thread, TaggedObject *obj, bool noAllocate,
2392                                                         bool *isCallGetter)
2393 {
2394     CString result = "";
2395     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
2396 
2397     JSHandle<JSTaggedValue> contructorKey = globalConst->GetHandledConstructorString();
2398     JSTaggedValue objConstructor = ObjectFastOperator::GetPropertyByName(thread, JSTaggedValue(obj),
2399                                                                          contructorKey.GetTaggedValue(), noAllocate,
2400                                                                          isCallGetter);
2401     if (*isCallGetter) {
2402         return "JSObject";
2403     }
2404 
2405     if (!objConstructor.IsJSFunction()) {
2406         return "JSObject";
2407     }
2408 
2409     JSFunctionBase *func = JSFunctionBase::Cast(objConstructor.GetTaggedObject());
2410     Method *method = Method::Cast(func->GetMethod().GetTaggedObject());
2411     MethodLiteral *methodLiteral = method->GetMethodLiteral();
2412     if (methodLiteral == nullptr) {
2413         return "JSObject";
2414     }
2415     const JSPandaFile *jsPandaFile = method->GetJSPandaFile();
2416     panda_file::File::EntityId methodId = methodLiteral->GetMethodId();
2417     const CString &nameStr = MethodLiteral::ParseFunctionNameToCString(jsPandaFile, methodId);
2418     const CString &moduleStr = method->GetRecordNameStr();
2419 
2420     if (!moduleStr.empty()) {
2421         result.append(moduleStr).append(" ");
2422     }
2423     if (nameStr.empty()) {
2424         result.append("JSObject");
2425     } else {
2426         result.append(nameStr);
2427     }
2428     DebugInfoExtractor *debugExtractor =
2429         JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
2430     if (debugExtractor == nullptr) {
2431         return result;
2432     }
2433     int32_t line = debugExtractor->GetFristLine(methodId);
2434     std::string fileName = debugExtractor->GetSourceFile(methodId);
2435     return result.append("(").append(fileName).append(std::to_string(line)).append(")");
2436 }
2437 
SpeciesConstructor(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & defaultConstructor)2438 JSHandle<JSTaggedValue> JSObject::SpeciesConstructor(JSThread *thread, const JSHandle<JSObject> &obj,
2439                                                      const JSHandle<JSTaggedValue> &defaultConstructor)
2440 {
2441     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
2442     // Assert: Type(O) is Object.
2443     ASSERT_PRINT(obj->IsECMAObject(), "obj must be js object");
2444 
2445     // Let C be Get(O, "constructor").
2446     JSHandle<JSTaggedValue> contructorKey = globalConst->GetHandledConstructorString();
2447     JSHandle<JSTaggedValue> objConstructor(JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(obj),
2448         contructorKey).GetValue());
2449     // ReturnIfAbrupt(C).
2450     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
2451     return SlowSpeciesConstructor(thread, objConstructor, defaultConstructor);
2452 }
2453 
SlowSpeciesConstructor(JSThread * thread,const JSHandle<JSTaggedValue> & objConstructor,const JSHandle<JSTaggedValue> & defaultConstructor)2454 JSHandle<JSTaggedValue> JSObject::SlowSpeciesConstructor(JSThread *thread,
2455                                                          const JSHandle<JSTaggedValue> &objConstructor,
2456                                                          const JSHandle<JSTaggedValue> &defaultConstructor)
2457 {
2458     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
2459     if (objConstructor->IsUndefined()) {
2460         return defaultConstructor;
2461     }
2462     // If Type(C) is not Object, throw a TypeError exception.
2463     if (!objConstructor->IsECMAObject()) {
2464         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is not Object",
2465                                     JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
2466     }
2467     // Let S be Get(C, @@species).
2468     JSHandle<JSTaggedValue> speciesSymbol = env->GetSpeciesSymbol();
2469     JSHandle<JSTaggedValue> speciesConstructor = GetProperty(thread, objConstructor, speciesSymbol).GetValue();
2470     // ReturnIfAbrupt(S).
2471     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
2472     // If S is either undefined or null, return defaultConstructor.
2473     if (speciesConstructor->IsUndefined() || speciesConstructor->IsNull()) {
2474         return defaultConstructor;
2475     }
2476     // If IsConstructor(S) is true, return S.
2477     if (speciesConstructor->IsConstructor()) {
2478         return speciesConstructor;
2479     }
2480     // Throw a TypeError exception.
2481     THROW_TYPE_ERROR_AND_RETURN(thread, "Is not Constructor",
2482                                 JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
2483     return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception());
2484 }
2485 
2486 // 6.2.4.6 CompletePropertyDescriptor ( Desc )
CompletePropertyDescriptor(const JSThread * thread,PropertyDescriptor & desc)2487 void PropertyDescriptor::CompletePropertyDescriptor(const JSThread *thread, PropertyDescriptor &desc)
2488 {
2489     // 1. ReturnIfAbrupt(Desc).
2490     // 2. Assert: Desc is a Property Descriptor
2491     // 3. Let like be Record{[[Value]]: undefined, [[Writable]]: false, [[Get]]: undefined, [[Set]]: undefined,
2492     // [[Enumerable]]: false, [[Configurable]]: false}.
2493     // 4. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then
2494     if (!desc.IsAccessorDescriptor()) {
2495         // a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to like.[[Value]].
2496         // b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]] to like.[[Writable]].
2497         if (!desc.HasValue()) {
2498             desc.SetValue(JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
2499         }
2500         if (!desc.HasWritable()) {
2501             desc.SetWritable(false);
2502         }
2503     } else {
2504         // a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to like.[[Get]].
2505         // b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to like.[[Set]].
2506         // Default value of Get and Set is undefined.
2507     }
2508     // 6. If Desc does not have an [[Enumerable]] field, set Desc.[[Enumerable]] to like.[[Enumerable]].
2509     // 7. If Desc does not have a [[Configurable]] field, set Desc.[[Configurable]] to like.[[Configurable]].
2510     if (!desc.HasEnumerable()) {
2511         desc.SetEnumerable(false);
2512     }
2513     if (!desc.HasConfigurable()) {
2514         desc.SetConfigurable(false);
2515     }
2516 }
2517 
2518 // static
2519 // When receiver has no elements and there is no enum cache and elements on receiver's prototype chain,
2520 // the enum cache is a simple enum cache.
2521 // When receiver and receiver's prototype chain have no elements, and the prototype is not modified,
2522 // the enum cache is a enum cache with protochain
IsSimpleEnumCacheValid(JSTaggedValue receiver)2523 bool JSObject::IsSimpleEnumCacheValid(JSTaggedValue receiver)
2524 {
2525     DISALLOW_GARBAGE_COLLECTION;
2526     uint32_t numOfElements = JSObject::Cast(receiver.GetTaggedObject())->GetNumberOfElements();
2527     if (numOfElements > 0) {
2528         return false;
2529     }
2530 
2531     JSTaggedValue current = JSObject::GetPrototype(receiver);
2532     while (current.IsHeapObject()) {
2533         JSObject *currentObj = JSObject::Cast(current.GetTaggedObject());
2534         uint32_t numOfCurrentElements = currentObj->GetNumberOfElements();
2535         if (numOfCurrentElements > 0) {
2536             return false;
2537         }
2538         JSHClass *hclass = currentObj->GetJSHClass();
2539         JSTaggedValue protoEnumCache = hclass->GetEnumCache();
2540         if (!protoEnumCache.IsUndefined()) {
2541             return false;
2542         }
2543         current = JSObject::GetPrototype(current);
2544     }
2545     return true;
2546 }
2547 
IsEnumCacheWithProtoChainInfoValid(JSTaggedValue receiver)2548 bool JSObject::IsEnumCacheWithProtoChainInfoValid(JSTaggedValue receiver)
2549 {
2550     DISALLOW_GARBAGE_COLLECTION;
2551     // check elements of receiver
2552     uint32_t numOfElements = JSObject::Cast(receiver.GetTaggedObject())->GetNumberOfElements();
2553     if (numOfElements > 0) {
2554         return false;
2555     }
2556     // check protochain keys
2557     JSTaggedValue proto = JSObject::GetPrototype(receiver);
2558     if (!proto.IsECMAObject()) {
2559         return false;
2560     }
2561     JSTaggedValue protoChangeMarker = proto.GetTaggedObject()->GetClass()->GetProtoChangeMarker();
2562     if (!protoChangeMarker.IsProtoChangeMarker()) {
2563         return false;
2564     }
2565     if (ProtoChangeMarker::Cast(protoChangeMarker.GetTaggedObject())->GetHasChanged()) {
2566         return false;
2567     }
2568     // check protochain elements
2569     JSTaggedValue current = proto;
2570     while (current.IsHeapObject()) {
2571         JSObject *currentObj = JSObject::Cast(current.GetTaggedObject());
2572         uint32_t numOfCurrentElements = currentObj->GetNumberOfElements();
2573         if (numOfCurrentElements > 0) {
2574             return false;
2575         }
2576         current = JSObject::GetPrototype(current);
2577     }
2578     return true;
2579 }
2580 
TryGetEnumCache(JSThread * thread,JSTaggedValue obj)2581 JSTaggedValue JSObject::TryGetEnumCache(JSThread *thread, JSTaggedValue obj)
2582 {
2583     if (obj.IsSlowKeysObject() || obj.GetTaggedObject()->GetClass()->IsDictionaryMode()) {
2584         return JSTaggedValue::Undefined();
2585     }
2586     JSTaggedValue enumCache = obj.GetTaggedObject()->GetClass()->GetEnumCache();
2587     EnumCacheKind kind = JSObject::GetEnumCacheKind(thread, enumCache);
2588     bool isEnumCacheValid = false;
2589     switch (kind) {
2590         case EnumCacheKind::SIMPLE:
2591             isEnumCacheValid = IsSimpleEnumCacheValid(obj);
2592             break;
2593         case EnumCacheKind::PROTOCHAIN:
2594             isEnumCacheValid = IsEnumCacheWithProtoChainInfoValid(obj);
2595             break;
2596         default:
2597             break;
2598     }
2599     if (!isEnumCacheValid) {
2600         return JSTaggedValue::Undefined();
2601     }
2602     return enumCache;
2603 }
2604 
2605 // 13.7.5.15 EnumerateObjectProperties ( O )
EnumerateObjectProperties(JSThread * thread,const JSHandle<JSTaggedValue> & obj)2606 JSHandle<JSForInIterator> JSObject::EnumerateObjectProperties(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
2607 {
2608     JSHandle<JSTaggedValue> object;
2609     if (obj->IsString()) {
2610         JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2611         object = JSHandle<JSTaggedValue>::Cast(JSPrimitiveRef::StringCreate(thread, obj, undefined));
2612     } else {
2613         object = JSTaggedValue::ToPrototypeOrObj(thread, obj);
2614     }
2615 
2616     JSMutableHandle<JSTaggedValue> keys(thread, JSTaggedValue::Undefined());
2617     JSMutableHandle<JSTaggedValue> cachedHclass(thread, JSTaggedValue::Undefined());
2618     if (object->IsNull() || object->IsUndefined()) {
2619         JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2620         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2621         keys.Update(factory->EmptyArray());
2622         return factory->NewJSForinIterator(undefined, keys, cachedHclass);
2623     }
2624     keys.Update(TryGetEnumCache(thread, object.GetTaggedValue()));
2625     if (!keys->IsUndefined()) {
2626         cachedHclass.Update(JSTaggedValue(JSHandle<JSObject>::Cast(object)->GetJSHClass()));
2627         return thread->GetEcmaVM()->GetFactory()->NewJSForinIterator(object, keys, cachedHclass);
2628     }
2629     return LoadEnumerateProperties(thread, object);
2630 }
2631 
LoadEnumerateProperties(JSThread * thread,const JSHandle<JSTaggedValue> & object)2632 JSHandle<JSForInIterator> JSObject::LoadEnumerateProperties(JSThread *thread, const JSHandle<JSTaggedValue> &object)
2633 {
2634     PropertyAccessor accessor(thread, object);
2635     JSHandle<JSTaggedValue> fastKeys = accessor.GetKeysFast();
2636     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSForInIterator, thread);
2637     JSMutableHandle<JSTaggedValue> keys(thread, JSTaggedValue::Undefined());
2638     JSMutableHandle<JSTaggedValue> cachedHclass(thread, JSTaggedValue::Undefined());
2639     if (fastKeys->IsUndefined()) {
2640         keys.Update(accessor.GetKeysSlow());
2641         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSForInIterator, thread);
2642     } else {
2643         keys.Update(fastKeys);
2644         cachedHclass.Update(accessor.GetCachedHclass());
2645     }
2646     return thread->GetEcmaVM()->GetFactory()->NewJSForinIterator(object, keys, cachedHclass);
2647 }
2648 
DefinePropertyByLiteral(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool useForClass)2649 void JSObject::DefinePropertyByLiteral(JSThread *thread, const JSHandle<JSObject> &obj,
2650                                        const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
2651                                        bool useForClass)
2652 {
2653     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
2654     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2655     PropertyAttributes attr = useForClass ? PropertyAttributes::Default(true, false, true)
2656                                           : PropertyAttributes::Default();
2657 
2658     if (value->IsAccessorData()) {
2659         attr.SetIsAccessor(true);
2660     }
2661 
2662     uint32_t index = 0;
2663     if (UNLIKELY(JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
2664         AddElementInternal(thread, obj, index, value, attr);
2665         return;
2666     }
2667     LOG_ECMA(FATAL) << "this branch is unreachable";
2668     UNREACHABLE();
2669 }
2670 
DefineSetter(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)2671 void JSObject::DefineSetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2672                             const JSHandle<JSTaggedValue> &value)
2673 {
2674     ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2675     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2676     ObjectOperator op(thread, obj, key, OperatorType::OWN);
2677     ASSERT(op.IsFound());
2678     op.DefineSetter(value);
2679 }
2680 
DefineGetter(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)2681 void JSObject::DefineGetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2682                             const JSHandle<JSTaggedValue> &value)
2683 {
2684     ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2685     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2686     ObjectOperator op(thread, obj, key, OperatorType::OWN);
2687     ASSERT(op.IsFound());
2688     op.DefineGetter(value);
2689 }
2690 
CreateObjectFromProperties(const JSThread * thread,const JSHandle<TaggedArray> & properties,JSTaggedValue ihcVal)2691 JSHandle<JSObject> JSObject::CreateObjectFromProperties(const JSThread *thread, const JSHandle<TaggedArray> &properties,
2692                                                         JSTaggedValue ihcVal)
2693 {
2694     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2695     size_t length = properties->GetLength();
2696     uint32_t propsLen = 0;
2697     for (size_t i = 0; i < length; i += 2) {  // 2: skip a pair of key and value
2698         if (properties->Get(i).IsHole()) {
2699             break;
2700         }
2701         propsLen++;
2702     }
2703     if (propsLen <= PropertyAttributes::MAX_FAST_PROPS_CAPACITY) {
2704         JSHandle<JSHClass> hclass;
2705         bool isLiteral = false;
2706         if (ihcVal.IsJSHClass()) {
2707             hclass = JSHandle<JSHClass>(thread, ihcVal);
2708         } else {
2709             hclass = factory->GetObjectLiteralHClass(properties, propsLen);
2710             isLiteral = true;
2711         }
2712         if (hclass->IsTS()) {
2713             if (CheckPropertiesForRep(properties, propsLen, hclass)) {
2714                 return CreateObjectFromPropertiesByIHClass(thread, properties, propsLen, hclass);
2715             } else if (!isLiteral) {
2716                 hclass = factory->GetObjectLiteralHClass(properties, propsLen);
2717                 // if check failed, get literal object again
2718                 return CreateObjectFromPropertiesByIHClass(thread, properties, propsLen, hclass);
2719             }
2720         }
2721         return CreateObjectFromProperties(thread, hclass, properties, propsLen);
2722     } else {
2723         JSHandle<JSObject> obj = factory->NewEmptyJSObject(0); // 0: no inline field
2724         ElementsKind oldKind = obj->GetJSHClass()->GetElementsKind();
2725         JSHClass::TransitionToDictionary(thread, obj);
2726         JSObject::TryMigrateToGenericKindForJSObject(thread, obj, oldKind);
2727 
2728         JSMutableHandle<NameDictionary> dict(
2729             thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(propsLen)));
2730         JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
2731         JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
2732         for (size_t i = 0; i < propsLen; i++) {
2733             PropertyAttributes attr = PropertyAttributes::Default();
2734             // 2: literal contains a pair of key-value
2735             valueHandle.Update(properties->Get(i * 2 + 1));
2736             // 2: literal contains a pair of key-value
2737             keyHandle.Update(properties->Get(i * 2));
2738             JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
2739             dict.Update(newDict);
2740         }
2741         obj->SetProperties(thread, dict);
2742         return obj;
2743     }
2744 }
2745 
CreateObjectFromProperties(const JSThread * thread,const JSHandle<JSHClass> & hclass,const JSHandle<TaggedArray> & properties,uint32_t propsLen)2746 JSHandle<JSObject> JSObject::CreateObjectFromProperties(const JSThread *thread,
2747                                                         const JSHandle<JSHClass> &hclass,
2748                                                         const JSHandle<TaggedArray> &properties,
2749                                                         uint32_t propsLen)
2750 {
2751     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2752     JSHandle<JSObject> obj = factory->NewOldSpaceObjLiteralByHClass(hclass);
2753     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
2754 
2755     if (thread->IsPGOProfilerEnable()) {
2756         // PGO need to track TrackType
2757         JSHClass *oldHC = obj->GetJSHClass();
2758         LayoutInfo *layoutInfo = LayoutInfo::Cast(oldHC->GetLayout().GetTaggedObject());
2759         for (size_t i = 0; i < propsLen; i++) {
2760             auto value = properties->Get(i * 2 + 1);
2761             auto attr = layoutInfo->GetAttr(i);
2762             if (attr.UpdateTrackType(value) && !oldHC->IsJSShared()) {
2763                 layoutInfo->SetNormalAttr(thread, i, attr);
2764             }
2765             obj->SetPropertyInlinedProps(thread, i, value);
2766         }
2767     } else {
2768         for (size_t i = 0; i < propsLen; i++) {
2769             // 2: literal contains a pair of key-value
2770             obj->SetPropertyInlinedProps(thread, i, properties->Get(i * 2 + 1));
2771         }
2772     }
2773     return obj;
2774 }
2775 
CreateObjectFromPropertiesByIHClass(const JSThread * thread,const JSHandle<TaggedArray> & properties,uint32_t propsLen,const JSHandle<JSHClass> & ihc)2776 JSHandle<JSObject> JSObject::CreateObjectFromPropertiesByIHClass(const JSThread *thread,
2777                                                                  const JSHandle<TaggedArray> &properties,
2778                                                                  uint32_t propsLen,
2779                                                                  const JSHandle<JSHClass> &ihc)
2780 {
2781     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2782 
2783     JSHandle<JSObject> obj = factory->NewOldSpaceObjLiteralByHClass(ihc);
2784     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
2785     auto layout = LayoutInfo::Cast(ihc->GetLayout().GetTaggedObject());
2786     for (size_t i = 0; i < propsLen; i++) {
2787         auto attr = layout->GetAttr(i);
2788         auto value = JSObject::ConvertValueWithRep(attr, properties->Get(i * 2 + 1));
2789         ASSERT(value.first);
2790         obj->SetPropertyInlinedPropsWithRep(thread, i, value.second);
2791     }
2792     return obj;
2793 }
2794 
CheckPropertiesForRep(const JSHandle<TaggedArray> & properties,uint32_t propsLen,const JSHandle<JSHClass> & ihc)2795 bool JSObject::CheckPropertiesForRep(
2796     const JSHandle<TaggedArray> &properties, uint32_t propsLen, const JSHandle<JSHClass> &ihc)
2797 {
2798     auto layout = LayoutInfo::Cast(ihc->GetLayout().GetTaggedObject());
2799     for (size_t i = 0; i < propsLen; i++) {
2800         auto attr = layout->GetAttr(i);
2801         auto value = JSObject::ConvertValueWithRep(attr, properties->Get(i * 2 + 1));
2802         // If value.first is false, indicating that value cannot be converted to the expected value of
2803         // representation. For example, the representation is INT, but the value type is string.
2804         if (!value.first) {
2805             return false;
2806         }
2807     }
2808     return true;
2809 }
2810 
AddAccessor(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<AccessorData> & value,PropertyAttributes attr)2811 void JSObject::AddAccessor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2812                            const JSHandle<AccessorData> &value, PropertyAttributes attr)
2813 {
2814     ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2815     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2816     ASSERT_PRINT(attr.IsAccessor(), "Attr is not AccessorData");
2817     ObjectOperator op(thread, obj, key, OperatorType::OWN);
2818     ASSERT(!op.IsFound());
2819     op.AddProperty(JSHandle<JSObject>::Cast(obj), JSHandle<JSTaggedValue>(value), attr);
2820 }
2821 
UpdatePropertyInDictionary(const JSThread * thread,JSTaggedValue key,JSTaggedValue value)2822 bool JSObject::UpdatePropertyInDictionary(const JSThread *thread, JSTaggedValue key, JSTaggedValue value)
2823 {
2824     [[maybe_unused]] DisallowGarbageCollection noGc;
2825     NameDictionary *dict = NameDictionary::Cast(GetProperties().GetTaggedObject());
2826     int entry = dict->FindEntry(key);
2827     if (entry == -1) {
2828         return false;
2829     }
2830     dict->UpdateValue(thread, entry, value);
2831     return true;
2832 }
2833 
TrimInlinePropsSpace(const JSThread * thread,const JSHandle<JSObject> & object,uint32_t numberInlinedProps)2834 void JSObject::TrimInlinePropsSpace(const JSThread *thread, const JSHandle<JSObject> &object,
2835                                     uint32_t numberInlinedProps)
2836 {
2837     if (numberInlinedProps > 0) {
2838         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2839         uint32_t newSize = object->GetClass()->GetObjectSize();
2840         size_t trimBytes = numberInlinedProps * JSTaggedValue::TaggedTypeSize();
2841         factory->FillFreeObject(ToUintPtr(*object) + newSize, trimBytes, RemoveSlots::YES, ToUintPtr(*object));
2842     }
2843 }
2844 
2845 // The hash field may be a hash value, FunctionExtraInfo(JSNativePointer) or TaggedArray
SetHash(const JSThread * thread,int32_t hash,const JSHandle<ECMAObject> & obj)2846 void ECMAObject::SetHash(const JSThread *thread, int32_t hash, const JSHandle<ECMAObject> &obj)
2847 {
2848     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(*obj, HASH_OFFSET);
2849     JSTaggedValue value(hashField);
2850     if (value.IsHeapObject()) {
2851         // Hash position reserve in advance.
2852         if (value.IsTaggedArray()) {
2853             TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2854             array->Set(thread, array->GetExtraLength() + HASH_INDEX, JSTaggedValue(hash));
2855         } else if (value.IsNativePointer()) { // FunctionExtraInfo
2856             JSHandle<JSTaggedValue> nativePointer(thread, value);
2857             JSHandle<TaggedArray> newArray =
2858                 thread->GetEcmaVM()->GetFactory()->NewTaggedArray(RESOLVED_MAX_SIZE);
2859             newArray->SetExtraLength(0);
2860             newArray->Set(thread, HASH_INDEX, JSTaggedValue(hash));
2861             newArray->Set(thread, FUNCTION_EXTRA_INDEX, nativePointer.GetTaggedValue());
2862             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2863         } else {
2864             LOG_ECMA(FATAL) << "this branch is unreachable";
2865             UNREACHABLE();
2866         }
2867     } else {
2868         Barriers::SetPrimitive<JSTaggedType>(*obj, HASH_OFFSET, JSTaggedValue(hash).GetRawData());
2869     }
2870 }
2871 
GetHash() const2872 int32_t ECMAObject::GetHash() const
2873 {
2874     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2875     JSTaggedValue value(hashField);
2876     if (value.IsHeapObject()) {
2877         if (value.IsTaggedArray()) {
2878             TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2879             return array->Get(array->GetExtraLength() + HASH_INDEX).GetInt();
2880         } else {
2881             // Default is 0
2882             return 0;
2883         }
2884     }
2885     return value.GetInt();
2886 }
2887 
HasHash() const2888 bool ECMAObject::HasHash() const
2889 {
2890     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2891     JSTaggedValue value(hashField);
2892     if (value.IsInt() && value.GetInt() == 0) {
2893         return false;
2894     }
2895     return true;
2896 }
2897 
GetNativePointerField(int32_t index) const2898 void *ECMAObject::GetNativePointerField(int32_t index) const
2899 {
2900     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2901     JSTaggedValue value(hashField);
2902     if (value.IsTaggedArray()) {
2903         auto array = TaggedArray::Cast(value);
2904         if (static_cast<int32_t>(array->GetExtraLength()) > index) {
2905             auto jsValue = array->Get(index);
2906             if (UNLIKELY(!jsValue.IsJSNativePointer())) {
2907                 LOG_FULL(ERROR) << "jsValue is not js native pointer";
2908                 return nullptr;
2909             }
2910             auto pointer = JSNativePointer::Cast(jsValue.GetTaggedObject());
2911             return pointer->GetExternalPointer();
2912         }
2913     }
2914     return nullptr;
2915 }
2916 
SetNativePointerField(const JSThread * thread,int32_t index,void * nativePointer,const NativePointerCallback & callBack,void * data,size_t nativeBindingsize,Concurrent isConcurrent)2917 void ECMAObject::SetNativePointerField(const JSThread *thread, int32_t index, void *nativePointer,
2918     const NativePointerCallback &callBack, void *data, size_t nativeBindingsize, Concurrent isConcurrent)
2919 {
2920     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2921     JSTaggedValue value(hashField);
2922     if (value.IsTaggedArray()) {
2923         JSHandle<TaggedArray> array(thread, value);
2924         if (static_cast<int32_t>(array->GetExtraLength()) > index) {
2925             EcmaVM *vm = thread->GetEcmaVM();
2926             JSHandle<JSTaggedValue> current = JSHandle<JSTaggedValue>(thread, array->Get(thread, index));
2927             JSHandle<JSTaggedValue> obj(thread, this);
2928             if (!current->IsHole() && nativePointer == nullptr) {
2929                 // Try to remove native pointer if exists.
2930                 vm->RemoveFromNativePointerList(*JSHandle<JSNativePointer>(current));
2931                 array->Set(thread, index, JSTaggedValue::Hole());
2932             } else if (obj->IsJSShared()) {
2933                 JSHandle<JSNativePointer> pointer =
2934                     vm->GetFactory()->NewSJSNativePointer(nativePointer, callBack, data, false, nativeBindingsize);
2935                 array->Set(thread, index, pointer.GetTaggedValue());
2936             } else {
2937                 JSHandle<JSNativePointer> pointer = vm->GetFactory()->NewJSNativePointer(
2938                     nativePointer, callBack, data, false, nativeBindingsize, isConcurrent);
2939                 array->Set(thread, index, pointer.GetTaggedValue());
2940             }
2941         }
2942     }
2943 }
2944 
GetNativePointerFieldCount() const2945 int32_t ECMAObject::GetNativePointerFieldCount() const
2946 {
2947     int32_t len = 0;
2948     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2949     JSTaggedValue value(hashField);
2950     if (value.IsTaggedArray()) {
2951         TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2952         len = static_cast<int32_t>(array->GetExtraLength());
2953     }
2954     return len;
2955 }
2956 
SetNativePointerFieldCount(const JSThread * thread,int32_t count)2957 void ECMAObject::SetNativePointerFieldCount(const JSThread *thread, int32_t count)
2958 {
2959     if (count == 0) {
2960         return;
2961     }
2962     JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2963     JSHandle<JSTaggedValue> value(thread, JSTaggedValue(hashField));
2964     JSHandle<ECMAObject> obj(thread, this);
2965     JSHandle<JSTaggedValue> object(obj);
2966     bool isShared = object->IsJSShared();
2967     if (value->IsHeapObject()) {
2968         if (value->IsTaggedArray()) {
2969             JSHandle<TaggedArray> array(value);
2970             // Native Pointer field count is fixed.
2971             if (array->GetExtraLength() == 0) {
2972                 JSHandle<TaggedArray> newArray =
2973                     isShared ? thread->GetEcmaVM()->GetFactory()->NewSTaggedArray(count + RESOLVED_MAX_SIZE)
2974                              : thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + RESOLVED_MAX_SIZE);
2975                 newArray->SetExtraLength(count);
2976                 newArray->Set(thread, count + HASH_INDEX, array->Get(HASH_INDEX));
2977                 newArray->Set(thread, count + FUNCTION_EXTRA_INDEX, array->Get(FUNCTION_EXTRA_INDEX));
2978                 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2979             }
2980         } else if (value->IsJSNativePointer()) {
2981             JSHandle<TaggedArray> newArray =
2982                 isShared ? thread->GetEcmaVM()->GetFactory()->NewSTaggedArray(count + RESOLVED_MAX_SIZE)
2983                          : thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + RESOLVED_MAX_SIZE);
2984             newArray->SetExtraLength(count);
2985             newArray->Set(thread, count + HASH_INDEX, JSTaggedValue(0));
2986             newArray->Set(thread, count + FUNCTION_EXTRA_INDEX, value);
2987             Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2988         } else {
2989             LOG_ECMA(FATAL) << "this branch is unreachable";
2990             UNREACHABLE();
2991         }
2992     } else {
2993         JSHandle<TaggedArray> newArray = isShared ? thread->GetEcmaVM()->GetFactory()->NewSTaggedArray(count + 1)
2994                                                   : thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + 1);
2995         newArray->SetExtraLength(count);
2996         newArray->Set(thread, count + HASH_INDEX, value);
2997         Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2998     }
2999 }
3000 
ElementsAndPropertiesIsEmpty() const3001 bool JSObject::ElementsAndPropertiesIsEmpty() const
3002 {
3003     if (TaggedArray::Cast(GetElements().GetTaggedObject())->GetLength() == 0 &&
3004         TaggedArray::Cast(GetProperties().GetTaggedObject())->GetLength() == 0) {
3005         return true;
3006     }
3007     return false;
3008 }
3009 
TryMigrateToGenericKindForJSObject(const JSThread * thread,const JSHandle<JSObject> & obj,const ElementsKind oldKind)3010 void JSObject::TryMigrateToGenericKindForJSObject(const JSThread *thread, const JSHandle<JSObject> &obj,
3011                                                   const ElementsKind oldKind)
3012 {
3013     if (obj->IsJSArray() && HasMutantTaggedArrayElements(obj)) {
3014         Elements::MigrateArrayWithKind(thread, obj, oldKind, ElementsKind::GENERIC);
3015     }
3016 }
3017 }  // namespace panda::ecmascript
3018