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 ¤t, 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 ¤t, 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 ¤t)
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, ©LengthOfKeys, ©LengthOfElements);
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, ©LengthOfKeys, ©LengthOfElements);
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