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