• 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 #ifndef ECMASCRIPT_JSOBJECT_INL_H
17 #define ECMASCRIPT_JSOBJECT_INL_H
18 
19 #include "ecmascript/js_object.h"
20 
21 #include "ecmascript/element_accessor-inl.h"
22 #include "ecmascript/js_array.h"
23 #include "ecmascript/js_hclass-inl.h"
24 #include "ecmascript/js_tagged_value-inl.h"
25 #include "ecmascript/js_typed_array.h"
26 #include "ecmascript/object_operator.h"
27 #include "ecmascript/tagged_array-inl.h"
28 #include "ecmascript/tagged_queue.h"
29 #include "ecmascript/tagged_dictionary.h"
30 
31 namespace panda::ecmascript {
SetCallable(bool flag)32 inline void ECMAObject::SetCallable(bool flag)
33 {
34     GetClass()->SetCallable(flag);
35 }
36 
IsCallable()37 inline bool ECMAObject::IsCallable() const
38 {
39     return GetClass()->IsCallable();
40 }
41 
42 // JSObject
IsExtensible()43 inline bool JSObject::IsExtensible() const
44 {
45     return GetJSHClass()->IsExtensible();
46 }
47 
48 // static
FillElementsWithHoles(const JSThread * thread,const JSHandle<JSObject> & obj,uint32_t start,uint32_t end)49 inline void JSObject::FillElementsWithHoles(const JSThread *thread, const JSHandle<JSObject> &obj,
50                                             uint32_t start, uint32_t end)
51 {
52     if (start >= end) {
53         return;
54     }
55     JSHandle<JSTaggedValue> holeHandle(thread, JSTaggedValue::Hole());
56     for (uint32_t i = start; i < end; i++) {
57         ElementAccessor::Set(thread, obj, i, holeHandle, false);
58     }
59 }
60 
GetNonInlinedFastPropsCapacity()61 inline uint32_t JSObject::GetNonInlinedFastPropsCapacity() const
62 {
63     uint32_t inlineProps = GetJSHClass()->GetInlinedProperties();
64     return PropertyAttributes::MAX_FAST_PROPS_CAPACITY - inlineProps;
65 }
66 
IsJSGlobalObject()67 inline bool JSObject::IsJSGlobalObject() const
68 {
69     return GetJSHClass()->IsJSGlobalObject();
70 }
71 
IsConstructor()72 inline bool JSObject::IsConstructor() const
73 {
74     return GetJSHClass()->IsConstructor();
75 }
76 
IsECMAObject()77 inline bool JSObject::IsECMAObject() const
78 {
79     return GetJSHClass()->IsECMAObject();
80 }
81 
IsJSError()82 inline bool JSObject::IsJSError() const
83 {
84     return GetJSHClass()->IsJSError();
85 }
86 
IsArguments()87 inline bool JSObject::IsArguments() const
88 {
89     return GetJSHClass()->IsArguments();
90 }
91 
IsDate()92 inline bool JSObject::IsDate() const
93 {
94     return GetJSHClass()->IsDate();
95 }
96 
IsJSArray()97 inline bool JSObject::IsJSArray() const
98 {
99     return GetJSHClass()->IsJSArray();
100 }
101 
IsJSSArray()102 inline bool JSObject::IsJSSArray() const
103 {
104     return GetJSHClass()->IsJSSharedArray();
105 }
106 
IsJSShared()107 inline bool JSObject::IsJSShared() const
108 {
109     return GetJSHClass()->IsJSShared();
110 }
111 
IsJSMap()112 inline bool JSObject::IsJSMap() const
113 {
114     return GetJSHClass()->IsJSMap();
115 }
116 
IsJSSet()117 inline bool JSObject::IsJSSet() const
118 {
119     return GetJSHClass()->IsJSSet();
120 }
121 
IsJSRegExp()122 inline bool JSObject::IsJSRegExp() const
123 {
124     return GetJSHClass()->IsJSRegExp();
125 }
126 
IsJSFunction()127 inline bool JSObject::IsJSFunction() const
128 {
129     return GetJSHClass()->IsJSFunction();
130 }
131 
IsBoundFunction()132 inline bool JSObject::IsBoundFunction() const
133 {
134     return GetJSHClass()->IsJsBoundFunction();
135 }
136 
IsJSIntlBoundFunction()137 inline bool JSObject::IsJSIntlBoundFunction() const
138 {
139     return GetJSHClass()->IsJSIntlBoundFunction();
140 }
141 
IsProxyRevocFunction()142 inline bool JSObject::IsProxyRevocFunction() const
143 {
144     return GetJSHClass()->IsJSProxyRevocFunction();
145 }
146 
IsAccessorData()147 inline bool JSObject::IsAccessorData() const
148 {
149     return GetJSHClass()->IsAccessorData();
150 }
151 
IsJSGlobalEnv()152 inline bool JSObject::IsJSGlobalEnv() const
153 {
154     return GetJSHClass()->IsJsGlobalEnv();
155 }
156 
IsJSProxy()157 inline bool JSObject::IsJSProxy() const
158 {
159     return GetJSHClass()->IsJSProxy();
160 }
161 
IsGeneratorObject()162 inline bool JSObject::IsGeneratorObject() const
163 {
164     return GetJSHClass()->IsGeneratorObject();
165 }
166 
IsAsyncGeneratorObject()167 inline bool JSObject::IsAsyncGeneratorObject() const
168 {
169     return GetJSHClass()->IsAsyncGeneratorObject();
170 }
171 
IsForinIterator()172 inline bool JSObject::IsForinIterator() const
173 {
174     return GetJSHClass()->IsForinIterator();
175 }
176 
IsJSSetIterator()177 inline bool JSObject::IsJSSetIterator() const
178 {
179     return GetJSHClass()->IsJSSetIterator();
180 }
181 
IsJSRegExpIterator()182 inline bool JSObject::IsJSRegExpIterator() const
183 {
184     return GetJSHClass()->IsJSRegExpIterator();
185 }
186 
IsJSMapIterator()187 inline bool JSObject::IsJSMapIterator() const
188 {
189     return GetJSHClass()->IsJSMapIterator();
190 }
191 
IsJSArrayIterator()192 inline bool JSObject::IsJSArrayIterator() const
193 {
194     return GetJSHClass()->IsJSArrayIterator();
195 }
196 
IsJSAPIArrayListIterator()197 inline bool JSObject::IsJSAPIArrayListIterator() const
198 {
199     return GetJSHClass()->IsJSAPIArrayListIterator();
200 }
201 
IsJSAPIStackIterator()202 inline bool JSObject::IsJSAPIStackIterator() const
203 {
204     return GetJSHClass()->IsJSAPIStackIterator();
205 }
206 
IsJSAPIVectorIterator()207 inline bool JSObject::IsJSAPIVectorIterator() const
208 {
209     return GetJSHClass()->IsJSAPIVectorIterator();
210 }
211 
IsJSAPIBitVectorIterator()212 inline bool JSObject::IsJSAPIBitVectorIterator() const
213 {
214     return GetJSHClass()->IsJSAPIBitVectorIterator();
215 }
216 
IsJSAPILinkedListIterator()217 inline bool JSObject::IsJSAPILinkedListIterator() const
218 {
219     return GetJSHClass()->IsJSAPILinkedListIterator();
220 }
221 
IsJSAPIListIterator()222 inline bool JSObject::IsJSAPIListIterator() const
223 {
224     return GetJSHClass()->IsJSAPIListIterator();
225 }
226 
IsJSPrimitiveRef()227 inline bool JSObject::IsJSPrimitiveRef() const
228 {
229     return GetJSHClass()->IsJsPrimitiveRef();
230 }
231 
IsElementDict()232 inline bool JSObject::IsElementDict() const
233 {
234     return TaggedArray::Cast(GetElements().GetTaggedObject())->IsDictionaryMode();
235 }
236 
IsPropertiesDict()237 inline bool JSObject::IsPropertiesDict() const
238 {
239     return TaggedArray::Cast(GetProperties().GetTaggedObject())->IsDictionaryMode();
240 }
241 
IsTypedArray()242 inline bool JSObject::IsTypedArray() const
243 {
244     return GetJSHClass()->IsTypedArray();
245 }
246 
IsSharedTypedArray()247 inline bool JSObject::IsSharedTypedArray() const
248 {
249     return GetJSHClass()->IsJSSharedTypedArray();
250 }
251 
ConvertValueWithRep(PropertyAttributes attr,JSTaggedValue value)252 std::pair<bool, JSTaggedValue> JSObject::ConvertValueWithRep(PropertyAttributes attr, JSTaggedValue value)
253 {
254     if (attr.IsDoubleRep()) {
255         if (value.IsInt()) {
256             double doubleValue = value.GetInt();
257             return std::pair(true, JSTaggedValue(bit_cast<JSTaggedType>(doubleValue)));
258         } else if (value.IsDouble()) {
259             return std::pair(true, JSTaggedValue(bit_cast<JSTaggedType>(value.GetDouble())));
260         } else {
261             return std::pair(false, value);
262         }
263     } else if (attr.IsIntRep()) {
264         if (value.IsInt()) {
265             int intValue = value.GetInt();
266             return std::pair(true, JSTaggedValue(static_cast<JSTaggedType>(intValue)));
267         } else {
268             return std::pair(false, value);
269         }
270     }
271     return std::pair(true, value);
272 }
273 
SetPropertyInlinedPropsWithRep(const JSThread * thread,uint32_t index,JSTaggedValue value)274 void JSObject::SetPropertyInlinedPropsWithRep(const JSThread *thread, uint32_t index, JSTaggedValue value)
275 {
276     auto layout = LayoutInfo::Cast(GetJSHClass()->GetLayout().GetTaggedObject());
277     auto attr = layout->GetAttr(index);
278     if (attr.IsTaggedRep()) {
279         SetPropertyInlinedProps<true>(thread, index, value);
280     } else {
281         SetPropertyInlinedProps<false>(thread, index, value);
282     }
283 }
284 
285 template <size_t objectSize, uint32_t index, bool needBarrier>
SetPropertyInlinedPropsWithSize(const JSThread * thread,JSTaggedValue value)286 void JSObject::SetPropertyInlinedPropsWithSize(const JSThread *thread, JSTaggedValue value)
287 {
288     constexpr uint32_t offset = static_cast<uint32_t>(objectSize + index * JSTaggedValue::TaggedTypeSize());
289     if constexpr (needBarrier) {
290         SET_VALUE_WITH_BARRIER(thread, this, offset, value);
291     } else {
292         SET_VALUE_PRIMITIVE(this, offset, value);
293     }
294 }
295 
296 template <bool needBarrier>
SetPropertyInlinedProps(const JSThread * thread,uint32_t index,JSTaggedValue value)297 void JSObject::SetPropertyInlinedProps(const JSThread *thread, uint32_t index, JSTaggedValue value)
298 {
299     SetPropertyInlinedProps<needBarrier>(thread, GetJSHClass(), index, value);
300 }
301 
GetPropertyInlinedPropsWithRep(uint32_t index,PropertyAttributes attr)302 JSTaggedValue JSObject::GetPropertyInlinedPropsWithRep(uint32_t index, PropertyAttributes attr) const
303 {
304     return GetPropertyInlinedPropsWithRep(GetJSHClass(), index, attr);
305 }
306 
GetPropertyInlinedPropsWithRep(const JSHClass * hclass,uint32_t index,PropertyAttributes attr)307 JSTaggedValue JSObject::GetPropertyInlinedPropsWithRep(const JSHClass *hclass, uint32_t index,
308                                                        PropertyAttributes attr) const
309 {
310     auto value = GetPropertyInlinedProps(hclass, index);
311     if (attr.IsDoubleRep()) {
312         value = JSTaggedValue(bit_cast<double>(value.GetRawData()));
313     } else if (attr.IsIntRep()) {
314         value = JSTaggedValue(static_cast<int32_t>(value.GetRawData()));
315     }
316     return value;
317 }
318 
319 template <size_t objectSize, uint32_t index>
GetPropertyInlinedPropsWithSize()320 JSTaggedValue JSObject::GetPropertyInlinedPropsWithSize() const
321 {
322     constexpr uint32_t offset = static_cast<uint32_t>(objectSize + index * JSTaggedValue::TaggedTypeSize());
323     return JSTaggedValue(GET_VALUE(this, offset));
324 }
325 
GetPropertyInlinedProps(uint32_t index)326 JSTaggedValue JSObject::GetPropertyInlinedProps(uint32_t index) const
327 {
328     return GetPropertyInlinedProps(GetJSHClass(), index);
329 }
330 
331 template <bool needBarrier>
SetPropertyInlinedProps(const JSThread * thread,const JSHClass * hclass,uint32_t index,JSTaggedValue value)332 void JSObject::SetPropertyInlinedProps(const JSThread *thread, const JSHClass *hclass, uint32_t index,
333                                        JSTaggedValue value)
334 {
335     uint32_t offset = hclass->GetInlinedPropertiesOffset(index);
336     ASSERT(hclass->GetObjectSize() > offset);
337     if constexpr (needBarrier) {
338         SET_VALUE_WITH_BARRIER(thread, this, offset, value);
339     } else {
340         SET_VALUE_PRIMITIVE(this, offset, value);
341     }
342 }
343 
GetPropertyInlinedProps(const JSHClass * hclass,uint32_t index)344 JSTaggedValue JSObject::GetPropertyInlinedProps(const JSHClass *hclass, uint32_t index) const
345 {
346     uint32_t offset = hclass->GetInlinedPropertiesOffset(index);
347     return JSTaggedValue(GET_VALUE(this, offset));
348 }
349 
GetProperty(const JSHClass * hclass,PropertyAttributes attr)350 JSTaggedValue JSObject::GetProperty(const JSHClass *hclass, PropertyAttributes attr) const
351 {
352     if (attr.IsInlinedProps()) {
353         return GetPropertyInlinedPropsWithRep(hclass, attr.GetOffset(), attr);
354     }
355     TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
356     return array->Get(attr.GetOffset() - hclass->GetInlinedProperties());
357 }
358 
359 template <bool needBarrier>
SetProperty(const JSThread * thread,const JSHClass * hclass,PropertyAttributes attr,JSTaggedValue value)360 void JSObject::SetProperty(const JSThread *thread, const JSHClass *hclass, PropertyAttributes attr, JSTaggedValue value)
361 {
362     if (attr.IsInlinedProps()) {
363         SetPropertyInlinedProps<needBarrier>(thread, hclass, attr.GetOffset(), value);
364     } else {
365         TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
366         array->Set<needBarrier>(thread, attr.GetOffset() - hclass->GetInlinedProperties(), value);
367     }
368 }
369 
ShouldTransToDict(uint32_t capacity,uint32_t index)370 inline bool JSObject::ShouldTransToDict(uint32_t capacity, uint32_t index)
371 {
372     if (index < capacity) {
373         return false;
374     }
375 
376     if (index - capacity > MAX_GAP) {
377         return true;
378     }
379 
380     if (index >= static_cast<uint32_t>(INT32_MAX)) {
381         return true;
382     }
383 
384     if (capacity >= MIN_GAP) {
385         return index > capacity * FAST_ELEMENTS_FACTOR;
386     }
387 
388     return false;
389 }
390 
ShouldTransToFastElements(JSThread * thread,TaggedArray * elements,uint32_t capacity,uint32_t index)391 inline bool JSObject::ShouldTransToFastElements(JSThread *thread, TaggedArray *elements,
392                                                 uint32_t capacity, uint32_t index)
393 {
394     JSHandle<NumberDictionary> dictionary(thread, elements);
395     if (index >= static_cast<uint32_t>(INT32_MAX)) {
396         return false;
397     }
398     // Turn fast if only saves 50% space.
399     if (static_cast<uint32_t>(dictionary->GetLength()) * SHOULD_TRANS_TO_FAST_ELEMENTS_FACTOR >= capacity ||
400         static_cast<uint64_t>(dictionary->NextEnumerationIndex(thread)) >
401         PropertyAttributes::DictionaryOrderField::MaxValue()) {
402         return true;
403     }
404     return false;
405 }
406 
ComputeElementCapacity(uint32_t oldCapacity,bool isNew)407 inline uint32_t JSObject::ComputeElementCapacity(uint32_t oldCapacity, bool isNew)
408 {
409     uint32_t newCapacity = isNew ? oldCapacity : (oldCapacity + (oldCapacity >> 1U));
410     return newCapacity > MIN_ELEMENTS_LENGTH ? newCapacity : MIN_ELEMENTS_LENGTH;
411 }
412 
ComputeElementCapacityHighGrowth(uint32_t oldCapacity)413 inline uint32_t JSObject::ComputeElementCapacityHighGrowth(uint32_t oldCapacity)
414 {
415     uint32_t newCapacity = oldCapacity * 2;
416     return newCapacity > MIN_ELEMENTS_LENGTH ? newCapacity : MIN_ELEMENTS_LENGTH;
417 }
418 
ComputeElementCapacityWithHint(uint32_t oldCapacity,uint32_t hint)419 inline uint32_t JSObject::ComputeElementCapacityWithHint(uint32_t oldCapacity, uint32_t hint)
420 {
421     uint32_t newCapacity = 0;
422     if ((oldCapacity >= hint) || (hint < MIN_ELEMENTS_HINT_LENGTH) || (hint >= MAX_ELEMENTS_HINT_LENGTH)) {
423         return newCapacity;
424     }
425     if ((hint / oldCapacity) <= ELEMENTS_HINT_FACTOR) {
426         newCapacity = hint;
427     }
428     return newCapacity;
429 }
430 
ComputeNonInlinedFastPropsCapacity(JSThread * thread,uint32_t oldCapacity,uint32_t maxNonInlinedFastPropsCapacity)431 inline uint32_t JSObject::ComputeNonInlinedFastPropsCapacity(JSThread *thread, uint32_t oldCapacity,
432                                                              uint32_t maxNonInlinedFastPropsCapacity)
433 {
434     uint32_t newCapacity = oldCapacity + thread->GetPropertiesGrowStep();
435     return newCapacity > maxNonInlinedFastPropsCapacity ? maxNonInlinedFastPropsCapacity : newCapacity;
436 }
437 
438 // static
439 template<ElementTypes types>
CreateListFromArrayLike(JSThread * thread,const JSHandle<JSTaggedValue> & obj)440 JSHandle<JSTaggedValue> JSObject::CreateListFromArrayLike(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
441 {
442     // 3. If Type(obj) is not Object, throw a TypeError exception.
443     if (!obj->IsECMAObject()) {
444         THROW_TYPE_ERROR_AND_RETURN(thread, "CreateListFromArrayLike must accept object",
445                                     JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
446     }
447     if (obj->IsTypedArray()) {
448         uint32_t len = JSHandle<JSTypedArray>::Cast(obj)->GetArrayLength();
449         JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(len);
450         JSTypedArray::FastCopyElementToArray(thread, obj, array);
451         // c. ReturnIfAbrupt(next).
452         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
453         return JSHandle<JSTaggedValue>(array);
454     }
455     // 4. Let len be ToLength(Get(obj, "length")).
456     JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
457 
458     JSHandle<JSTaggedValue> value = GetProperty(thread, obj, lengthKeyHandle).GetValue();
459     JSTaggedNumber number = JSTaggedValue::ToLength(thread, value);
460     // 5. ReturnIfAbrupt(len).
461     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
462     if (number.GetNumber() > MAX_ELEMENT_INDEX) {
463         THROW_TYPE_ERROR_AND_RETURN(thread, "len is bigger than 2^32 - 1",
464                                     JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
465     }
466 
467     uint32_t len = number.ToUint32();
468     // 6. Let list be an empty List.
469     JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(len);
470     // 8. Repeat while index < len
471     for (uint32_t i = 0; i < len; i++) {
472         JSTaggedValue next = JSTaggedValue::GetProperty(thread, obj, i).GetValue().GetTaggedValue();
473         // c. ReturnIfAbrupt(next).
474         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
475 
476         if constexpr (types == ElementTypes::STRING_AND_SYMBOL) {
477             if (!next.IsString() && !next.IsSymbol()) {
478                 THROW_TYPE_ERROR_AND_RETURN(thread, "CreateListFromArrayLike: not an element of elementTypes",
479                                             JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
480             }
481         }
482 
483         array->Set(thread, i, next);
484     }
485     return JSHandle<JSTaggedValue>(array);
486 }
487 
ShouldGetValueFromBox(ObjectOperator * op)488 inline JSTaggedValue JSObject::ShouldGetValueFromBox(ObjectOperator *op)
489 {
490     JSTaggedValue result = op->GetValue();
491     if (result.IsPropertyBox()) {
492         result = PropertyBox::Cast(result.GetTaggedObject())->GetValue();
493     }
494     return result;
495 }
496 
CheckHClassHit(const JSHandle<JSObject> & obj,const JSHandle<JSHClass> & cls)497 inline bool JSObject::CheckHClassHit(const JSHandle<JSObject> &obj, const JSHandle<JSHClass> &cls)
498 {
499     return obj->GetJSHClass() == *cls;
500 }
501 
SetValuesOrEntries(JSThread * thread,const JSHandle<TaggedArray> & prop,uint32_t index,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,PropertyKind kind)502 inline uint32_t JSObject::SetValuesOrEntries(JSThread *thread, const JSHandle<TaggedArray> &prop, uint32_t index,
503                                              const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
504                                              PropertyKind kind)
505 {
506     if (kind == PropertyKind::VALUE) {
507         prop->Set(thread, index++, value);
508         return index;
509     }
510     JSHandle<TaggedArray> keyValue = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(2);  // 2: key-value pair
511     keyValue->Set(thread, 0, key);
512     keyValue->Set(thread, 1, value);
513     JSHandle<JSArray> entry = JSArray::CreateArrayFromList(thread, keyValue);
514     prop->Set(thread, index++, entry.GetTaggedValue());
515     return index;
516 }
517 
SetEnumCacheKind(JSThread * thread,TaggedArray * array,EnumCacheKind kind)518 inline void JSObject::SetEnumCacheKind(JSThread *thread, TaggedArray *array, EnumCacheKind kind)
519 {
520     array->Set(thread, EnumCache::ENUM_CACHE_KIND_OFFSET, JSTaggedValue(static_cast<uint8_t>(kind)));
521 }
522 
GetEnumCacheKind(JSThread * thread,TaggedArray * array)523 inline EnumCacheKind JSObject::GetEnumCacheKind(JSThread *thread, TaggedArray *array)
524 {
525     return static_cast<EnumCacheKind>(array->Get(thread, EnumCache::ENUM_CACHE_KIND_OFFSET).GetInt());
526 }
527 
GetEnumCacheKind(JSThread * thread,JSTaggedValue enumCache)528 inline EnumCacheKind JSObject::GetEnumCacheKind(JSThread *thread, JSTaggedValue enumCache)
529 {
530     if (enumCache.IsUndefinedOrNull()) {
531         return EnumCacheKind::NONE;
532     }
533     JSTaggedValue emptyArray = thread->GlobalConstants()->GetEmptyArray();
534     if (enumCache == emptyArray) {
535         return EnumCacheKind::SIMPLE;
536     }
537     TaggedArray *array = TaggedArray::Cast(enumCache.GetTaggedObject());
538     return JSObject::GetEnumCacheKind(thread, array);
539 }
540 
GetPrototype(JSTaggedValue obj)541 inline JSTaggedValue JSObject::GetPrototype(JSTaggedValue obj)
542 {
543     JSHClass *hclass = obj.GetTaggedObject()->GetClass();
544     return hclass->GetPrototype();
545 }
546 
IsDepulicateKeys(JSThread * thread,JSHandle<TaggedArray> keys,int32_t lastLength,JSHandle<TaggedQueue> shadowQueue,JSHandle<JSTaggedValue> key)547 inline bool JSObject::IsDepulicateKeys(JSThread *thread, JSHandle<TaggedArray> keys, int32_t lastLength,
548                                        JSHandle<TaggedQueue> shadowQueue, JSHandle<JSTaggedValue> key)
549 {
550     if (lastLength < 0) {
551         return false;
552     }
553     JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
554     for (int32_t i = EnumCache::ENUM_CACHE_HEADER_SIZE; i < lastLength; i++) {
555         value.Update(keys->Get(i));
556         bool has = JSTaggedValue::Equal(thread, value, key);
557         if (has) {
558             return true;
559         }
560     }
561 
562     uint32_t shadowSize = shadowQueue->Size();
563     for (uint32_t i = 0; i < shadowSize; i++) {
564         value.Update(shadowQueue->Get(i));
565         bool has = JSTaggedValue::Equal(thread, value, key);
566         if (has) {
567             return true;
568         }
569     }
570     return false;
571 }
572 
ClearHasDeleteProperty(JSHandle<JSTaggedValue> object)573 inline void JSObject::ClearHasDeleteProperty(JSHandle<JSTaggedValue> object)
574 {
575     object->GetTaggedObject()->GetClass()->SetHasDeleteProperty(false);
576 }
577 
GetOwnEnumerableNamesInFastMode(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t * copyLengthOfKeys,uint32_t * copyLengthOfElements)578 inline std::pair<JSHandle<TaggedArray>, JSHandle<TaggedArray>> JSObject::GetOwnEnumerableNamesInFastMode(
579     JSThread *thread, const JSHandle<JSObject> &obj, uint32_t *copyLengthOfKeys, uint32_t *copyLengthOfElements)
580 {
581     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
582     std::pair<uint32_t, uint32_t> numOfKeys = obj->GetNumberOfEnumKeys();
583     uint32_t numOfEnumKeys = numOfKeys.first;
584     uint32_t numOfElements = obj->GetNumberOfElements(thread);
585     JSHandle<TaggedArray> elementArray = numOfElements > 0 ? JSObject::GetEnumElementKeys(
586         thread, obj, 0, numOfElements, copyLengthOfElements) : factory->EmptyArray();
587     JSHandle<TaggedArray> keyArray = numOfEnumKeys > 0 ? JSObject::GetAllEnumKeys(
588         thread, obj, numOfEnumKeys, copyLengthOfKeys) : factory->EmptyArray();
589     return std::make_pair(keyArray, elementArray);
590 }
591 
HasMutantTaggedArrayElements(const JSHandle<JSObject> & obj)592 inline bool JSObject::HasMutantTaggedArrayElements(const JSHandle<JSObject> &obj)
593 {
594     return obj->GetElements().IsMutantTaggedArray();
595 }
596 }  //  namespace panda::ecmascript
597 #endif  // ECMASCRIPT_JSOBJECT_INL_H
598