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