1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/js_object-inl.h"
17
18 #include "ecmascript/accessor_data.h"
19 #include "ecmascript/ecma_macros.h"
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/filter_helper.h"
22 #include "ecmascript/global_dictionary-inl.h"
23 #include "ecmascript/global_env.h"
24 #include "ecmascript/js_for_in_iterator.h"
25 #include "ecmascript/js_hclass.h"
26 #include "ecmascript/js_iterator.h"
27 #include "ecmascript/js_primitive_ref.h"
28 #include "ecmascript/js_thread.h"
29 #include "ecmascript/object_factory.h"
30 #include "ecmascript/object_fast_operator-inl.h"
31 #include "ecmascript/pgo_profiler/pgo_profiler.h"
32 #include "ecmascript/property_attributes.h"
33 #include "ecmascript/tagged_array-inl.h"
34
35 namespace panda::ecmascript {
PropertyAttributes(const PropertyDescriptor & desc)36 PropertyAttributes::PropertyAttributes(const PropertyDescriptor &desc)
37 {
38 DISALLOW_GARBAGE_COLLECTION;
39 if (desc.HasWritable()) {
40 SetWritable(desc.IsWritable());
41 }
42
43 if (desc.HasEnumerable()) {
44 SetEnumerable(desc.IsEnumerable());
45 }
46
47 if (desc.HasConfigurable()) {
48 SetConfigurable(desc.IsConfigurable());
49 }
50
51 if (desc.IsAccessorDescriptor()) {
52 SetIsAccessor(true);
53 }
54 // internal accessor
55 if (desc.HasValue() && desc.GetValue()->IsAccessor()) {
56 SetIsAccessor(true);
57 }
58 }
59
GetCallTarget() const60 Method *ECMAObject::GetCallTarget() const
61 {
62 const TaggedObject *obj = this;
63 ASSERT(JSTaggedValue(obj).IsJSFunctionBase() || JSTaggedValue(obj).IsJSProxy());
64
65 JSTaggedValue value;
66 if (JSTaggedValue(obj).IsJSFunctionBase()) {
67 value = JSFunctionBase::ConstCast(obj)->GetMethod();
68 } else {
69 value = JSProxy::ConstCast(obj)->GetMethod();
70 }
71 return Method::Cast(value.GetTaggedObject());
72 }
73
GrowElementsCapacity(const JSThread * thread,const JSHandle<JSObject> & obj,uint32_t capacity)74 JSHandle<TaggedArray> JSObject::GrowElementsCapacity(const JSThread *thread, const JSHandle<JSObject> &obj,
75 uint32_t capacity)
76 {
77 uint32_t newCapacity = ComputeElementCapacity(capacity);
78 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
79 JSHandle<TaggedArray> oldElements(thread, obj->GetElements());
80 uint32_t oldLength = oldElements->GetLength();
81 JSHandle<TaggedArray> newElements = factory->CopyArray(oldElements, oldLength, newCapacity);
82
83 obj->SetElements(thread, newElements);
84 return newElements;
85 }
86
IterableToList(JSThread * thread,const JSHandle<JSTaggedValue> & items,JSTaggedValue method)87 JSHandle<JSTaggedValue> JSObject::IterableToList(JSThread *thread, const JSHandle<JSTaggedValue> &items,
88 JSTaggedValue method)
89 {
90 // 1. If method is present, then
91 // a. Let iteratorRecord be ? GetIterator(items, sync, method).
92 // 2. Else,
93 // a. Let iteratorRecord be ? GetIterator(items, sync).
94 JSHandle<JSTaggedValue> iteratorRecord;
95 JSHandle<JSTaggedValue> methodHandle(thread, method);
96 if (!methodHandle->IsUndefined()) {
97 iteratorRecord = JSIterator::GetIterator(thread, items, methodHandle);
98 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
99 } else {
100 iteratorRecord = JSIterator::GetIterator(thread, items);
101 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
102 }
103 // 3. Let values be a new empty List.
104 // 4. Let next be true.
105 JSHandle<JSArray> array = JSHandle<JSArray>::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
106 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
107 JSHandle<JSTaggedValue> valuesList = JSHandle<JSTaggedValue>::Cast(array);
108 JSMutableHandle<JSTaggedValue> next(thread, JSTaggedValue::True());
109 // 5. Repeat, while next is not false,
110 // a. Set next to ? IteratorStep(iteratorRecord).
111 // b. If next is not false, then
112 // i. Let nextValue be ? IteratorValue(next).
113 // ii. Append nextValue to the end of the List values.
114 uint32_t k = 0;
115 while (!next->IsFalse()) {
116 next.Update(JSIterator::IteratorStep(thread, iteratorRecord).GetTaggedValue());
117 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
118 if (!next->IsFalse()) {
119 JSHandle<JSTaggedValue> nextValue(JSIterator::IteratorValue(thread, next));
120 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
121 JSArray::FastSetPropertyByValue(thread, valuesList, k, nextValue);
122 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
123 k++;
124 }
125 }
126 // 6. Return values.
127 return valuesList;
128 }
129
IsRegExp(JSThread * thread,const JSHandle<JSTaggedValue> & argument)130 bool JSObject::IsRegExp(JSThread *thread, const JSHandle<JSTaggedValue> &argument)
131 {
132 if (!argument->IsECMAObject()) {
133 return false;
134 }
135 JSHandle<JSTaggedValue> matchSymbol = thread->GetEcmaVM()->GetGlobalEnv()->GetMatchSymbol();
136 JSHandle<JSTaggedValue> isRegexp = JSObject::GetProperty(thread, argument, matchSymbol).GetValue();
137 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
138 if (!isRegexp->IsUndefined()) {
139 return isRegexp->ToBoolean();
140 }
141 JSHandle<JSObject> argumentObj = JSHandle<JSObject>::Cast(argument);
142 return argumentObj->IsJSRegExp();
143 }
144
TransitionToDictionary(const JSThread * thread,const JSHandle<JSObject> & receiver)145 JSHandle<NameDictionary> JSObject::TransitionToDictionary(const JSThread *thread, const JSHandle<JSObject> &receiver)
146 {
147 JSHandle<TaggedArray> array(thread, receiver->GetProperties());
148 JSHandle<JSHClass> jshclass(thread, receiver->GetJSHClass());
149 ASSERT(!jshclass->IsDictionaryMode());
150 uint32_t propNumber = jshclass->NumberOfProps();
151
152 ASSERT(!jshclass->GetLayout().IsNull());
153 JSHandle<LayoutInfo> layoutInfoHandle(thread, jshclass->GetLayout());
154 ASSERT(layoutInfoHandle->GetLength() != 0);
155 JSMutableHandle<NameDictionary> dict(
156 thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(propNumber)));
157 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
158 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
159 uint32_t numberInlinedProps = jshclass->GetInlinedProperties();
160 for (uint32_t i = 0; i < propNumber; i++) {
161 JSTaggedValue key = layoutInfoHandle->GetKey(i);
162 PropertyAttributes attr = layoutInfoHandle->GetAttr(i);
163 ASSERT(i == attr.GetOffset());
164 JSTaggedValue value;
165
166 if (i < numberInlinedProps) {
167 value = receiver->GetPropertyInlinedPropsWithRep(i, attr);
168 // If delete a property in hclass which has subtyping info and not prototype, only set value as hole and
169 // not remove. When transition to dictionary, exclude it.
170 if (value.IsHole()) {
171 continue;
172 }
173 } else {
174 value = array->Get(i - numberInlinedProps);
175 }
176
177 attr.SetBoxType(PropertyBoxType::UNDEFINED);
178 valueHandle.Update(value);
179 keyHandle.Update(key);
180 JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
181 dict.Update(newDict);
182 }
183
184 receiver->SetProperties(thread, dict);
185 // change HClass
186 JSHClass::TransitionToDictionary(thread, receiver);
187
188 // trim in-obj properties space
189 if (numberInlinedProps > 0) {
190 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
191 uint32_t newSize = receiver->GetClass()->GetObjectSize();
192 size_t trimBytes = numberInlinedProps * JSTaggedValue::TaggedTypeSize();
193 factory->FillFreeObject(ToUintPtr(*receiver) + newSize, trimBytes, RemoveSlots::YES, ToUintPtr(*receiver));
194 }
195
196 return dict;
197 }
198
ElementsToDictionary(const JSThread * thread,JSHandle<JSObject> obj)199 void JSObject::ElementsToDictionary(const JSThread *thread, JSHandle<JSObject> obj)
200 {
201 JSHandle<TaggedArray> elements(thread, obj->GetElements());
202 ASSERT(!obj->GetJSHClass()->IsDictionaryElement());
203 uint32_t length = elements->GetLength();
204 JSMutableHandle<NumberDictionary> dict(thread, NumberDictionary::Create(thread));
205 auto attr = PropertyAttributes(PropertyAttributes::GetDefaultAttributes());
206 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
207 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue ::Undefined());
208 for (uint32_t i = 0; i < length; i++) {
209 JSTaggedValue value = elements->Get(i);
210 if (value.IsHole()) {
211 continue;
212 }
213 key.Update(JSTaggedValue(i));
214 valueHandle.Update(value);
215 JSHandle<NumberDictionary> newDict = NumberDictionary::PutIfAbsent(thread, dict, key, valueHandle, attr);
216 dict.Update(newDict);
217 }
218 obj->SetElements(thread, dict);
219
220 JSHClass::TransitionElementsToDictionary(thread, obj);
221 }
222
IsArrayLengthWritable(JSThread * thread,const JSHandle<JSObject> & receiver)223 bool JSObject::IsArrayLengthWritable(JSThread *thread, const JSHandle<JSObject> &receiver)
224 {
225 auto *hclass = receiver->GetJSHClass();
226 if (!hclass->IsDictionaryMode()) {
227 LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
228 PropertyAttributes attr(layoutInfo->GetAttr(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
229 return attr.IsWritable();
230 }
231 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
232 ObjectOperator op(thread, receiver, lengthKey, OperatorType::OWN);
233 return op.GetAttr().IsWritable();
234 }
235
AddElementInternal(JSThread * thread,const JSHandle<JSObject> & receiver,uint32_t index,const JSHandle<JSTaggedValue> & value,PropertyAttributes attr)236 bool JSObject::AddElementInternal(JSThread *thread, const JSHandle<JSObject> &receiver, uint32_t index,
237 const JSHandle<JSTaggedValue> &value, PropertyAttributes attr)
238 {
239 bool isDictionary = receiver->GetJSHClass()->IsDictionaryElement();
240 ElementsKind kind = ElementsKind::NONE;
241 if (receiver->IsJSArray()) {
242 DISALLOW_GARBAGE_COLLECTION;
243 JSArray *arr = JSArray::Cast(*receiver);
244 uint32_t oldLength = arr->GetArrayLength();
245 if (index >= oldLength) {
246 if (!IsArrayLengthWritable(thread, receiver)) {
247 return false;
248 }
249 arr->SetArrayLength(thread, index + 1);
250 if (index > oldLength) {
251 kind = ElementsKind::HOLE;
252 }
253 }
254 }
255 thread->NotifyStableArrayElementsGuardians(receiver, StableArrayChangeKind::NOT_PROTO);
256
257 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
258 if (isDictionary) {
259 ASSERT(elements->IsDictionaryMode());
260 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(static_cast<int32_t>(index)));
261 JSHandle<NumberDictionary> newDict =
262 NumberDictionary::Put(thread, JSHandle<NumberDictionary>(thread, elements), keyHandle, value, attr);
263 receiver->SetElements(thread, newDict);
264 return true;
265 }
266
267 uint32_t capacity = elements->GetLength();
268 if (index >= capacity || !attr.IsDefaultAttributes()) {
269 if (ShouldTransToDict(capacity, index) || !attr.IsDefaultAttributes()) {
270 JSObject::ElementsToDictionary(thread, receiver);
271 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(static_cast<int32_t>(index)));
272 JSHandle<NumberDictionary> dict(thread, receiver->GetElements());
273 JSHandle<NumberDictionary> newKey = NumberDictionary::Put(thread, dict, keyHandle, value, attr);
274 receiver->SetElements(thread, newKey);
275 return true;
276 }
277 elements = *JSObject::GrowElementsCapacity(thread, receiver, index + 1);
278 }
279 elements->Set(thread, index, value);
280 JSHClass::TransitToElementsKind(thread, receiver, value, kind);
281 return true;
282 }
283
DeletePropertyInternal(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,uint32_t index)284 void JSObject::DeletePropertyInternal(JSThread *thread, const JSHandle<JSObject> &obj,
285 const JSHandle<JSTaggedValue> &key, uint32_t index)
286 {
287 JSHandle<TaggedArray> array(thread, obj->GetProperties());
288
289 if (obj->IsJSGlobalObject()) {
290 JSHandle<GlobalDictionary> dictHandle(thread, obj->GetProperties());
291 JSHandle<GlobalDictionary> newDict = GlobalDictionary::Remove(thread, dictHandle, index);
292 obj->SetProperties(thread, newDict);
293 return;
294 }
295
296 if (!array->IsDictionaryMode()) {
297 JSHClass *hclass = obj->GetJSHClass();
298 // To maintain TS inherit info, not change hclass, just set hole.
299 if (hclass->HasTSSubtyping() && !hclass->IsPrototype()) {
300 obj->SetPropertyInlinedProps(thread, index, JSTaggedValue::Hole());
301 return;
302 }
303 JSHandle<NameDictionary> dictHandle(TransitionToDictionary(thread, obj));
304 int entry = dictHandle->FindEntry(key.GetTaggedValue());
305 ASSERT(entry != -1);
306 JSHandle<NameDictionary> newDict = NameDictionary::Remove(thread, dictHandle, entry);
307 obj->SetProperties(thread, newDict);
308 return;
309 }
310
311 JSHandle<NameDictionary> dictHandle(array);
312 JSHandle<NameDictionary> newDict = NameDictionary::Remove(thread, dictHandle, index);
313 obj->SetProperties(thread, newDict);
314 }
315
GetAllKeys(const JSThread * thread,const JSHandle<JSObject> & obj,int offset,const JSHandle<TaggedArray> & keyArray)316 void JSObject::GetAllKeys(const JSThread *thread, const JSHandle<JSObject> &obj, int offset,
317 const JSHandle<TaggedArray> &keyArray)
318
319 {
320 TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
321 if (!array->IsDictionaryMode()) {
322 int end = static_cast<int>(obj->GetJSHClass()->NumberOfProps());
323 if (end > 0) {
324 LayoutInfo::Cast(obj->GetJSHClass()->GetLayout().GetTaggedObject())
325 ->GetAllKeys(thread, end, offset, *keyArray, obj);
326 }
327 return;
328 }
329
330 if (obj->IsJSGlobalObject()) {
331 GlobalDictionary *dict = GlobalDictionary::Cast(array);
332 return dict->GetAllKeys(thread, offset, *keyArray);
333 }
334
335 NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
336 dict->GetAllKeys(thread, offset, *keyArray);
337 }
338
GetAllKeysByFilter(const JSThread * thread,const JSHandle<JSObject> & obj,uint32_t & keyArrayEffectivelength,const JSHandle<TaggedArray> & keyArray,uint32_t filter)339 void JSObject::GetAllKeysByFilter(const JSThread *thread, const JSHandle<JSObject> &obj,
340 uint32_t &keyArrayEffectivelength,
341 const JSHandle<TaggedArray> &keyArray,
342 uint32_t filter)
343 {
344 TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
345 if (!array->IsDictionaryMode()) {
346 uint32_t numberOfProps = obj->GetJSHClass()->NumberOfProps();
347 if (numberOfProps > 0) {
348 LayoutInfo::Cast(obj->GetJSHClass()->GetLayout().GetTaggedObject())->
349 GetAllKeysByFilter(thread, numberOfProps, keyArrayEffectivelength, *keyArray, obj, filter);
350 }
351 return;
352 }
353
354 if (obj->IsJSGlobalObject()) {
355 GlobalDictionary *dict = GlobalDictionary::Cast(array);
356 return dict->GetAllKeysByFilter(thread, keyArrayEffectivelength, *keyArray, filter);
357 }
358
359 NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
360 dict->GetAllKeysByFilter(thread, keyArrayEffectivelength, *keyArray, filter);
361 }
362
363 // For Serialization use. Does not support JSGlobalObject
GetAllKeys(const JSHandle<JSObject> & obj,std::vector<JSTaggedValue> & keyVector)364 void JSObject::GetAllKeys(const JSHandle<JSObject> &obj, std::vector<JSTaggedValue> &keyVector)
365 {
366 DISALLOW_GARBAGE_COLLECTION;
367 ASSERT_PRINT(!obj->IsJSGlobalObject(), "Do not support get key of JSGlobal Object");
368 TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
369 if (!array->IsDictionaryMode()) {
370 int end = static_cast<int>(obj->GetJSHClass()->NumberOfProps());
371 if (end > 0) {
372 LayoutInfo::Cast(obj->GetJSHClass()->GetLayout().GetTaggedObject())->GetAllKeys(end, keyVector, obj);
373 }
374 } else {
375 NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
376 dict->GetAllKeysIntoVector(keyVector);
377 }
378 }
379
GetAllEnumKeys(const JSThread * thread,const JSHandle<JSObject> & obj,int offset,uint32_t numOfKeys,uint32_t * keys)380 JSHandle<TaggedArray> JSObject::GetAllEnumKeys(const JSThread *thread, const JSHandle<JSObject> &obj, int offset,
381 uint32_t numOfKeys, uint32_t *keys)
382 {
383 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
384 if (obj->IsJSGlobalObject()) {
385 JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(numOfKeys);
386 GlobalDictionary *dict = GlobalDictionary::Cast(obj->GetProperties().GetTaggedObject());
387 dict->GetEnumAllKeys(thread, offset, *keyArray, keys);
388 return keyArray;
389 }
390
391 TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
392 if (!array->IsDictionaryMode()) {
393 JSHClass *jsHclass = obj->GetJSHClass();
394 JSTaggedValue enumCache = jsHclass->GetEnumCache();
395 if (!enumCache.IsNull()) {
396 auto keyArray = JSHandle<TaggedArray>(thread, enumCache);
397 *keys = keyArray->GetLength();
398 return keyArray;
399 }
400 JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(numOfKeys);
401 int end = static_cast<int>(jsHclass->NumberOfProps());
402 if (end > 0) {
403 LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject())
404 ->GetAllEnumKeys(thread, end, offset, *keyArray, keys, obj);
405 if (*keys == keyArray->GetLength()) {
406 jsHclass->SetEnumCache(thread, keyArray.GetTaggedValue());
407 }
408 }
409 return keyArray;
410 }
411
412 JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(numOfKeys);
413 NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
414 dict->GetAllEnumKeys(thread, offset, *keyArray, keys);
415 return keyArray;
416 }
417
GetAllEnumKeys(const JSThread * thread,const JSHandle<JSObject> & obj,int offset,const JSHandle<TaggedArray> & keyArray)418 void JSObject::GetAllEnumKeys(const JSThread *thread, const JSHandle<JSObject> &obj, int offset,
419 const JSHandle<TaggedArray> &keyArray)
420 {
421 TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
422 uint32_t keys = 0;
423 if (!array->IsDictionaryMode()) {
424 JSHClass *jsHclass = obj->GetJSHClass();
425 int end = static_cast<int>(jsHclass->NumberOfProps());
426 if (end > 0) {
427 LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject())
428 ->GetAllEnumKeys(thread, end, offset, *keyArray, &keys, obj);
429 }
430 return;
431 }
432 if (obj->IsJSGlobalObject()) {
433 GlobalDictionary *dict = GlobalDictionary::Cast(obj->GetProperties().GetTaggedObject());
434 dict->GetEnumAllKeys(thread, offset, *keyArray, &keys);
435 return;
436 }
437
438 NameDictionary *dict = NameDictionary::Cast(obj->GetProperties().GetTaggedObject());
439 dict->GetAllEnumKeys(thread, offset, *keyArray, &keys);
440 }
441
GetAllElementKeys(JSThread * thread,const JSHandle<JSObject> & obj,int offset,const JSHandle<TaggedArray> & keyArray)442 void JSObject::GetAllElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
443 const JSHandle<TaggedArray> &keyArray)
444 {
445 uint32_t elementIndex = 0;
446 if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
447 elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength() + static_cast<uint32_t>(offset);
448 for (uint32_t i = static_cast<uint32_t>(offset); i < elementIndex; ++i) {
449 auto key = base::NumberHelper::IntToEcmaString(thread, i);
450 keyArray->Set(thread, i, key);
451 }
452 }
453
454 JSHandle<TaggedArray> elements(thread, obj->GetElements());
455 if (!elements->IsDictionaryMode()) {
456 uint32_t elementsLen = elements->GetLength();
457 for (uint32_t i = 0, j = elementIndex; i < elementsLen; ++i) {
458 if (!elements->Get(i).IsHole()) {
459 auto key = base::NumberHelper::IntToEcmaString(thread, i);
460 keyArray->Set(thread, j++, key);
461 }
462 }
463 } else {
464 NumberDictionary::GetAllKeys(thread, JSHandle<NumberDictionary>(elements), elementIndex, keyArray);
465 }
466 }
467
GetAllElementKeysByFilter(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<TaggedArray> & keyArray,uint32_t & keyArrayEffectiveLength,uint32_t filter)468 void JSObject::GetAllElementKeysByFilter(JSThread *thread,
469 const JSHandle<JSObject> &obj,
470 const JSHandle<TaggedArray> &keyArray,
471 uint32_t &keyArrayEffectiveLength,
472 uint32_t filter)
473 {
474 ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
475 uint32_t elementIndex = 0;
476
477 // For strings attributes, only enumerable is true
478 if ((filter & NATIVE_ENUMERABLE) && obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
479 elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength();
480 for (uint32_t i = 0; i < elementIndex; ++i) {
481 keyArray->Set(thread, keyArrayEffectiveLength, JSTaggedValue(i));
482 keyArrayEffectiveLength++;
483 }
484 }
485
486 JSHandle<TaggedArray> elements(thread, obj->GetElements());
487 JSHandle<JSTaggedValue> objValue(obj);
488
489 if (!elements->IsDictionaryMode()) {
490 uint32_t elementsLen = elements->GetLength();
491 for (uint32_t i = 0; i < elementsLen; ++i) {
492 if (!elements->Get(i).IsHole()) {
493 ObjectOperator op(thread, objValue, i, OperatorType::OWN);
494 bool bIgnore = FilterHelper::IgnoreKeyByFilter<ObjectOperator>(op, filter);
495 if (bIgnore) {
496 continue;
497 }
498 keyArray->Set(thread, keyArrayEffectiveLength, JSTaggedValue(i));
499 keyArrayEffectiveLength++;
500 }
501 }
502 } else {
503 NumberDictionary::GetAllKeysByFilter(thread, JSHandle<NumberDictionary>(elements),
504 keyArrayEffectiveLength, keyArray, filter);
505 }
506 }
507
GetALLElementKeysIntoVector(const JSThread * thread,const JSHandle<JSObject> & obj,std::vector<JSTaggedValue> & keyVector)508 void JSObject::GetALLElementKeysIntoVector(const JSThread *thread, const JSHandle<JSObject> &obj,
509 std::vector<JSTaggedValue> &keyVector)
510 {
511 JSHandle<TaggedArray> elements(thread, obj->GetElements());
512 if (!elements->IsDictionaryMode()) {
513 uint32_t elementsLen = elements->GetLength();
514 for (uint32_t i = 0; i < elementsLen; ++i) {
515 if (!elements->Get(i).IsHole()) {
516 keyVector.emplace_back(JSTaggedValue(i));
517 }
518 }
519 } else {
520 JSHandle<NumberDictionary> dict = JSHandle<NumberDictionary>::Cast(elements);
521 dict->GetAllKeysIntoVector(keyVector);
522 }
523 }
524
GetEnumElementKeys(JSThread * thread,const JSHandle<JSObject> & obj,int offset,uint32_t numOfElements,uint32_t * keys)525 JSHandle<TaggedArray> JSObject::GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
526 uint32_t numOfElements, uint32_t *keys)
527 {
528 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
529 JSHandle<TaggedArray> elementArray = factory->NewTaggedArray(numOfElements);
530 uint32_t elementIndex = 0;
531 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
532
533 if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
534 elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength();
535 *keys += elementIndex;
536 elementIndex += static_cast<uint32_t>(offset);
537 for (uint32_t i = static_cast<uint32_t>(offset); i < elementIndex; ++i) {
538 keyHandle.Update(base::NumberHelper::IntToEcmaString(thread, i));
539 elementArray->Set(thread, i, keyHandle);
540 }
541 }
542
543 JSHandle<TaggedArray> arr(thread, obj->GetElements());
544 if (!arr->IsDictionaryMode()) {
545 uint32_t elementsLen = arr->GetLength();
546 uint32_t preElementIndex = elementIndex;
547 for (uint32_t i = 0; i < elementsLen; ++i) {
548 if (!arr->Get(i).IsHole()) {
549 keyHandle.Update(base::NumberHelper::IntToEcmaString(thread, i));
550 elementArray->Set(thread, elementIndex++, keyHandle);
551 }
552 }
553 *keys += (elementIndex - preElementIndex);
554 } else {
555 NumberDictionary::GetAllEnumKeys(thread, JSHandle<NumberDictionary>(arr), elementIndex, elementArray, keys);
556 }
557 return elementArray;
558 }
559
GetEnumElementKeys(JSThread * thread,const JSHandle<JSObject> & obj,int offset,const JSHandle<TaggedArray> & keyArray)560 void JSObject::GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset,
561 const JSHandle<TaggedArray> &keyArray)
562 {
563 uint32_t elementIndex = 0;
564 if (obj->IsJSPrimitiveRef() && JSPrimitiveRef::Cast(*obj)->IsString()) {
565 elementIndex = JSPrimitiveRef::Cast(*obj)->GetStringLength() + static_cast<uint32_t>(offset);
566 for (uint32_t i = static_cast<uint32_t>(offset); i < elementIndex; ++i) {
567 auto key = base::NumberHelper::IntToEcmaString(thread, i);
568 keyArray->Set(thread, i, key);
569 }
570 }
571
572 JSHandle<TaggedArray> elements(thread, obj->GetElements());
573 if (!elements->IsDictionaryMode()) {
574 uint32_t elementsLen = elements->GetLength();
575 for (uint32_t i = 0, j = elementIndex; i < elementsLen; ++i) {
576 if (!elements->Get(i).IsHole()) {
577 auto key = base::NumberHelper::IntToEcmaString(thread, i);
578 keyArray->Set(thread, j++, key);
579 }
580 }
581 } else {
582 uint32_t keys = 0;
583 NumberDictionary::GetAllEnumKeys(thread, JSHandle<NumberDictionary>(elements), elementIndex, keyArray, &keys);
584 }
585 }
586
GetNumberOfKeys()587 uint32_t JSObject::GetNumberOfKeys()
588 {
589 DISALLOW_GARBAGE_COLLECTION;
590 TaggedArray *array = TaggedArray::Cast(GetProperties().GetTaggedObject());
591
592 if (!array->IsDictionaryMode()) {
593 return GetJSHClass()->NumberOfProps();
594 }
595
596 return NameDictionary::Cast(array)->EntriesCount();
597 }
598
GlobalSetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool mayThrow)599 bool JSObject::GlobalSetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key,
600 const JSHandle<JSTaggedValue> &value, bool mayThrow)
601 {
602 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
603
604 ObjectOperator op(thread, key);
605 if (!op.IsFound()) {
606 PropertyAttributes attr = PropertyAttributes::Default(true, true, false);
607 op.SetAttr(attr);
608 }
609 return SetProperty(&op, value, mayThrow);
610 }
611
GetNumberOfElements()612 uint32_t JSObject::GetNumberOfElements()
613 {
614 DISALLOW_GARBAGE_COLLECTION;
615 uint32_t numOfElements = 0;
616 if (IsJSPrimitiveRef() && JSPrimitiveRef::Cast(this)->IsString()) {
617 numOfElements = JSPrimitiveRef::Cast(this)->GetStringLength();
618 }
619
620 TaggedArray *elements = TaggedArray::Cast(GetElements().GetTaggedObject());
621 if (!elements->IsDictionaryMode()) {
622 uint32_t elementsLen = elements->GetLength();
623 for (uint32_t i = 0; i < elementsLen; ++i) {
624 if (!elements->Get(i).IsHole()) {
625 numOfElements++;
626 }
627 }
628 } else {
629 numOfElements += static_cast<uint32_t>(NumberDictionary::Cast(elements)->EntriesCount());
630 }
631
632 return numOfElements;
633 }
634
635 // 9.1.9 [[Set]] ( P, V, Receiver)
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)636 bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
637 const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
638 {
639 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
640 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
641
642 // 2 ~ 4 findProperty in Receiver, Obj and its parents
643 ObjectOperator op(thread, obj, receiver, key);
644 return SetProperty(&op, value, mayThrow);
645 }
646
SetProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool mayThrow)647 bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
648 const JSHandle<JSTaggedValue> &value, bool mayThrow)
649 {
650 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid JSObject");
651 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
652
653 ObjectOperator op(thread, obj, key);
654 return SetProperty(&op, value, mayThrow);
655 }
656
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool mayThrow)657 bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
658 const JSHandle<JSTaggedValue> &value, bool mayThrow)
659 {
660 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
661 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
662
663 // 2 ~ 4 findProperty in Receiver, Obj and its parents
664 ObjectOperator op(thread, obj, key);
665 return SetProperty(&op, value, mayThrow);
666 }
667
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t index,const JSHandle<JSTaggedValue> & value,bool mayThrow)668 bool JSObject::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index,
669 const JSHandle<JSTaggedValue> &value, bool mayThrow)
670 {
671 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
672
673 ObjectOperator op(thread, obj, index);
674 return SetProperty(&op, value, mayThrow);
675 }
676
SetProperty(ObjectOperator * op,const JSHandle<JSTaggedValue> & value,bool mayThrow)677 bool JSObject::SetProperty(ObjectOperator *op, const JSHandle<JSTaggedValue> &value, bool mayThrow)
678 {
679 JSThread *thread = op->GetThread();
680
681 JSHandle<JSTaggedValue> receiver = op->GetReceiver();
682 JSHandle<JSTaggedValue> holder = op->GetHolder();
683 if (holder->IsJSProxy()) {
684 if (op->IsElement()) {
685 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(op->GetElementIndex()));
686 return JSProxy::SetProperty(thread, JSHandle<JSProxy>::Cast(holder), key, value, receiver, mayThrow);
687 }
688 return JSProxy::SetProperty(thread, JSHandle<JSProxy>::Cast(holder), op->GetKey(), value, receiver, mayThrow);
689 }
690
691 // When op is not found and is not set extra attributes
692 if (!op->IsFound() && op->IsPrimitiveAttr()) {
693 op->SetAsDefaultAttr();
694 }
695
696 bool isInternalAccessor = false;
697 if (op->IsAccessorDescriptor()) {
698 JSTaggedValue ret = ShouldGetValueFromBox(op);
699 isInternalAccessor = AccessorData::Cast(ret.GetTaggedObject())->IsInternal();
700 }
701
702 // 5. If IsDataDescriptor(ownDesc) is true, then
703 if (!op->IsAccessorDescriptor() || isInternalAccessor) {
704 if (!op->IsWritable()) {
705 if (mayThrow) {
706 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot assign to read only property", false);
707 }
708 return false;
709 }
710
711 if (!receiver->IsECMAObject()) {
712 if (mayThrow) {
713 THROW_TYPE_ERROR_AND_RETURN(thread, "Receiver is not a JSObject", false);
714 }
715 return false;
716 }
717
718 if (receiver->IsJSProxy()) {
719 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
720 if (op->IsElement()) {
721 key.Update(JSTaggedValue(op->GetElementIndex()));
722 } else {
723 key.Update(op->GetKey().GetTaggedValue());
724 }
725
726 PropertyDescriptor existDesc(thread);
727 JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>::Cast(receiver), key, existDesc);
728 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
729 if (!existDesc.IsEmpty()) {
730 if (existDesc.IsAccessorDescriptor()) {
731 return false;
732 }
733
734 if (!existDesc.IsWritable()) {
735 return false;
736 }
737
738 PropertyDescriptor valueDesc(thread, value);
739 return JSProxy::DefineOwnProperty(thread, JSHandle<JSProxy>::Cast(receiver), key, valueDesc);
740 }
741 return CreateDataProperty(thread, JSHandle<JSObject>(receiver), key, value);
742 }
743
744 // 5e. If existingDescriptor is not undefined, then
745 bool hasReceiver = false;
746 if (op->HasReceiver()) {
747 op->ReLookupPropertyInReceiver();
748 hasReceiver = true;
749 }
750 bool isSuccess = true;
751 if (op->IsFound() && !op->IsOnPrototype()) {
752 // i. If IsAccessorDescriptor(existingDescriptor) is true, return false.
753 if (op->IsAccessorDescriptor() && !isInternalAccessor) {
754 return false;
755 }
756
757 // ii. If existingDescriptor.[[Writable]] is false, return false.
758 if (!op->IsWritable()) {
759 if (mayThrow) {
760 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot assign to read only property", false);
761 }
762 return false;
763 }
764 isSuccess = op->UpdateDataValue(JSHandle<JSObject>(receiver), value, isInternalAccessor, mayThrow);
765 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, isSuccess);
766 } else {
767 // 5f. Else if Receiver does not currently have a property P, Return CreateDataProperty(Receiver, P, V).
768 if (!receiver->IsExtensible(thread)) {
769 if (mayThrow) {
770 THROW_TYPE_ERROR_AND_RETURN(thread, "receiver is not Extensible", false);
771 }
772 return false;
773 }
774 if (hasReceiver || isInternalAccessor) {
775 return op->AddProperty(JSHandle<JSObject>(receiver), value, PropertyAttributes::Default());
776 } else {
777 return op->AddProperty(JSHandle<JSObject>(receiver), value, op->GetAttr());
778 }
779 }
780 return isSuccess;
781 }
782 // 6. Assert: IsAccessorDescriptor(ownDesc) is true.
783 ASSERT(op->IsAccessorDescriptor());
784 // 8. If setter is undefined, return false.
785 JSTaggedValue ret = ShouldGetValueFromBox(op);
786 AccessorData *accessor = AccessorData::Cast(ret.GetTaggedObject());
787 return CallSetter(thread, *accessor, receiver, value, mayThrow);
788 }
789
CallSetter(JSThread * thread,const AccessorData & accessor,const JSHandle<JSTaggedValue> & receiver,const JSHandle<JSTaggedValue> & value,bool mayThrow)790 bool JSObject::CallSetter(JSThread *thread, const AccessorData &accessor, const JSHandle<JSTaggedValue> &receiver,
791 const JSHandle<JSTaggedValue> &value, bool mayThrow)
792 {
793 if (UNLIKELY(accessor.IsInternal())) {
794 return accessor.CallInternalSet(thread, JSHandle<JSObject>::Cast(receiver), value, mayThrow);
795 }
796 JSTaggedValue setter = accessor.GetSetter();
797 // 8. If setter is undefined, return false.
798 if (setter.IsUndefined()) {
799 if (mayThrow) {
800 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property when setter is undefined", false);
801 }
802 return false;
803 }
804
805 JSHandle<JSTaggedValue> func(thread, setter);
806 if (thread->IsPGOProfilerEnable()) {
807 auto profiler = thread->GetEcmaVM()->GetPGOProfiler();
808 profiler->ProfileCall(JSTaggedValue::VALUE_UNDEFINED, func.GetTaggedType());
809 }
810 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
811 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, receiver, undefined, 1);
812 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
813 info->SetCallArg(value.GetTaggedValue());
814 JSFunction::Call(info);
815
816 // 10. ReturnIfAbrupt(setterResult).
817 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
818
819 return true;
820 }
821
CallGetter(JSThread * thread,const AccessorData * accessor,const JSHandle<JSTaggedValue> & receiver)822 JSTaggedValue JSObject::CallGetter(JSThread *thread, const AccessorData *accessor,
823 const JSHandle<JSTaggedValue> &receiver)
824 {
825 JSTaggedValue getter = accessor->GetGetter();
826 // 7. If getter is undefined, return undefined.
827 if (getter.IsUndefined()) {
828 return JSTaggedValue::Undefined();
829 }
830
831 JSHandle<JSTaggedValue> func(thread, getter);
832 if (thread->IsPGOProfilerEnable()) {
833 auto profiler = thread->GetEcmaVM()->GetPGOProfiler();
834 profiler->ProfileCall(JSTaggedValue::VALUE_UNDEFINED, func.GetTaggedType());
835 }
836 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
837 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, receiver, undefined, 0);
838 JSTaggedValue res = JSFunction::Call(info);
839 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
840 return res;
841 }
842
843 // 9.1.8 [[Get]] (P, Receiver)
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)844 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
845 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
846 {
847 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
848 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
849
850 ObjectOperator op(thread, obj, receiver, key);
851 return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
852 }
853
GetProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key)854 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSObject> &obj,
855 const JSHandle<JSTaggedValue> &key)
856 {
857 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid JSObject");
858 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
859
860 ObjectOperator op(thread, obj, key);
861 return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
862 }
863
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)864 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
865 const JSHandle<JSTaggedValue> &key)
866 {
867 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
868 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
869
870 ObjectOperator op(thread, obj, key);
871 return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
872 }
873
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t index)874 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index)
875 {
876 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
877
878 ObjectOperator op(thread, obj, index);
879 return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
880 }
881
GetPropertyFromGlobal(JSThread * thread,const JSHandle<JSTaggedValue> & key)882 OperationResult JSObject::GetPropertyFromGlobal(JSThread *thread, const JSHandle<JSTaggedValue> &key)
883 {
884 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
885
886 ObjectOperator op(thread, key);
887 return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
888 }
889
GetProperty(JSThread * thread,ObjectOperator * op)890 JSTaggedValue JSObject::GetProperty(JSThread *thread, ObjectOperator *op)
891 {
892 JSHandle<JSTaggedValue> receiver = op->GetReceiver();
893 JSHandle<JSTaggedValue> holder = op->GetHolder();
894 if (holder->IsJSProxy()) {
895 if (op->IsElement()) {
896 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(op->GetElementIndex()));
897 return JSProxy::GetProperty(thread, JSHandle<JSProxy>::Cast(holder), key, receiver)
898 .GetValue()
899 .GetTaggedValue();
900 }
901 return JSProxy::GetProperty(thread, JSHandle<JSProxy>::Cast(holder), op->GetKey(), receiver)
902 .GetValue()
903 .GetTaggedValue();
904 }
905
906 // 4. If desc is undefined, then
907 if (!op->IsFound()) {
908 // 4c. If obj and parent is null, return undefined.
909 return JSTaggedValue::Undefined();
910 }
911 // 5. If IsDataDescriptor(desc) is true, return desc.[[Value]]
912 JSTaggedValue ret = ShouldGetValueFromBox(op);
913 if (!op->IsAccessorDescriptor()) {
914 return ret;
915 }
916
917 // 6. Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].
918 AccessorData *accessor = AccessorData::Cast(ret.GetTaggedObject());
919 // 8. Return Call(getter, Receiver).
920 if (UNLIKELY(accessor->IsInternal())) {
921 return accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(holder));
922 }
923 return CallGetter(thread, accessor, receiver);
924 }
925
DeleteProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key)926 bool JSObject::DeleteProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key)
927 {
928 // 1. Assert: IsPropertyKey(P) is true.
929 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
930 // 2. Let desc be O.[[GetOwnProperty]](P).
931
932 ObjectOperator op(thread, JSHandle<JSTaggedValue>(obj), key, OperatorType::OWN);
933
934 // 4. If desc is undefined, return true.
935 if (!op.IsFound()) {
936 return true;
937 }
938 // 5. If desc.[[Configurable]] is true, then
939 // a. Remove the own property with name P from O.
940 // b. Return true.
941 // 6. Return false.
942 if (op.IsConfigurable()) {
943 op.DeletePropertyInHolder();
944 obj->GetClass()->SetHasDeleteProperty(true);
945 return true;
946 }
947 return false;
948 }
949
GetOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)950 bool JSObject::GetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
951 PropertyDescriptor &desc)
952 {
953 return OrdinaryGetOwnProperty(thread, obj, key, desc);
954 }
955
GlobalGetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)956 bool JSObject::GlobalGetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
957 {
958 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
959 ObjectOperator op(thread, key, OperatorType::OWN);
960
961 if (!op.IsFound()) {
962 return false;
963 }
964
965 op.ToPropertyDescriptor(desc);
966
967 if (desc.HasValue()) {
968 PropertyBox *cell = PropertyBox::Cast(desc.GetValue().GetTaggedValue().GetTaggedObject());
969 JSHandle<JSTaggedValue> valueHandle(thread, cell->GetValue());
970 desc.SetValue(valueHandle);
971 }
972 ASSERT(!desc.GetValue()->IsInternalAccessor());
973 return true;
974 }
975
OrdinaryGetOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)976 bool JSObject::OrdinaryGetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
977 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
978 {
979 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
980 ObjectOperator op(thread, JSHandle<JSTaggedValue>(obj), key, OperatorType::OWN);
981
982 if (!op.IsFound()) {
983 return false;
984 }
985
986 op.ToPropertyDescriptor(desc);
987
988 if (desc.HasValue() && obj->IsJSGlobalObject()) {
989 JSTaggedValue val = desc.GetValue().GetTaggedValue();
990 if (val.IsPropertyBox()) {
991 PropertyBox *cell = PropertyBox::Cast(val.GetTaggedObject());
992 JSHandle<JSTaggedValue> valueHandle(thread, cell->GetValue());
993 desc.SetValue(valueHandle);
994 }
995 }
996
997 return true;
998 }
999
DefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)1000 bool JSObject::DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1001 const PropertyDescriptor &desc)
1002 {
1003 return OrdinaryDefineOwnProperty(thread, obj, key, desc);
1004 }
1005
DefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const PropertyDescriptor & desc)1006 bool JSObject::DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1007 const PropertyDescriptor &desc)
1008 {
1009 return OrdinaryDefineOwnProperty(thread, obj, index, desc);
1010 }
1011
1012 // 9.1.6.1 OrdinaryDefineOwnProperty (O, P, Desc)
OrdinaryDefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)1013 bool JSObject::OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
1014 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
1015 {
1016 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1017 // 1. Let current be O.[[GetOwnProperty]](P).
1018 JSHandle<JSTaggedValue> objValue(obj);
1019 ObjectOperator op(thread, objValue, key, OperatorType::OWN);
1020
1021 bool extensible = obj->IsExtensible();
1022 PropertyDescriptor current(thread);
1023 op.ToPropertyDescriptor(current);
1024 // 4. Return ValidateAndApplyPropertyDescriptor(O, P, extensible, Desc, current).
1025 return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current);
1026 }
1027
OrdinaryDefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const PropertyDescriptor & desc)1028 bool JSObject::OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1029 const PropertyDescriptor &desc)
1030 {
1031 JSHandle<JSTaggedValue> objValue(obj);
1032 ObjectOperator op(thread, objValue, index, OperatorType::OWN);
1033
1034 bool extensible = obj->IsExtensible();
1035 PropertyDescriptor current(thread);
1036 op.ToPropertyDescriptor(current);
1037 return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current);
1038 }
1039
1040 // 9.1.6.3 ValidateAndApplyPropertyDescriptor (O, P, extensible, Desc, current)
ValidateAndApplyPropertyDescriptor(ObjectOperator * op,bool extensible,const PropertyDescriptor & desc,const PropertyDescriptor & current)1041 bool JSObject::ValidateAndApplyPropertyDescriptor(ObjectOperator *op, bool extensible, const PropertyDescriptor &desc,
1042 const PropertyDescriptor ¤t)
1043 {
1044 // 2. If current is undefined, then
1045 if (current.IsEmpty()) {
1046 // 2a. If extensible is false, return false.
1047 if (!extensible) {
1048 return false;
1049 }
1050 if (!op->HasHolder()) {
1051 return true;
1052 }
1053
1054 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then
1055 PropertyAttributes attr(desc);
1056 bool success = false;
1057 if (!desc.IsAccessorDescriptor()) {
1058 success = op->AddPropertyInHolder(desc.GetValue(), attr);
1059 } else { // is AccessorDescriptor
1060 // may GC in NewAccessorData, so we need to handle getter and setter.
1061 JSThread *thread = op->GetThread();
1062 JSHandle<AccessorData> accessor = thread->GetEcmaVM()->GetFactory()->NewAccessorData();
1063 if (desc.HasGetter()) {
1064 accessor->SetGetter(thread, desc.GetGetter());
1065 }
1066
1067 if (desc.HasSetter()) {
1068 accessor->SetSetter(thread, desc.GetSetter());
1069 }
1070 success = op->AddPropertyInHolder(JSHandle<JSTaggedValue>::Cast(accessor), attr);
1071 }
1072
1073 return success;
1074 }
1075
1076 // 3. Return true, if every field in Desc is absent
1077 // 4. Return true, if every field in Desc also occurs in current and the value of every field in Desc is the
1078 // same value as the corresponding field in current when compared using the SameValue algorithm.
1079 if ((!desc.HasEnumerable() || desc.IsEnumerable() == current.IsEnumerable()) &&
1080 (!desc.HasConfigurable() || desc.IsConfigurable() == current.IsConfigurable()) &&
1081 (!desc.HasValue() || JSTaggedValue::SameValue(current.GetValue(), desc.GetValue())) &&
1082 (!desc.HasWritable() || (current.IsWritable() == desc.IsWritable())) &&
1083 (!desc.HasGetter() ||
1084 (current.HasGetter() && JSTaggedValue::SameValue(current.GetGetter(), desc.GetGetter()))) &&
1085 (!desc.HasSetter() ||
1086 (current.HasSetter() && JSTaggedValue::SameValue(current.GetSetter(), desc.GetSetter())))) {
1087 return true;
1088 }
1089
1090 // 5. If the [[Configurable]] field of current is false, then
1091 if (!current.IsConfigurable()) {
1092 // 5a. Return false, if the [[Configurable]] field of Desc is true.
1093 if (desc.HasConfigurable() && desc.IsConfigurable()) {
1094 return false;
1095 }
1096 // b. Return false, if the [[Enumerable]] field of Desc is present and the [[Enumerable]] fields of current
1097 // and Desc are the Boolean negation of each other.
1098 if (desc.HasEnumerable() && (desc.IsEnumerable() != current.IsEnumerable())) {
1099 return false;
1100 }
1101 }
1102
1103 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
1104 if (desc.IsGenericDescriptor()) {
1105 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have different results, then
1106 } else if (current.IsDataDescriptor() != desc.IsDataDescriptor()) {
1107 // 7a. Return false, if the [[Configurable]] field of current is false.
1108 if (!current.IsConfigurable()) {
1109 return false;
1110 }
1111 // 7b. If IsDataDescriptor(current) is true, then
1112 if (current.IsDataDescriptor()) {
1113 // 7bi. If O is not undefined, convert the property named P of object O from a data property to an
1114 // accessor property. Preserve the existing values of the converted property’s [[Configurable]] and
1115 // [[Enumerable]] attributes and set the rest of the property’s attributes to their default values.
1116 } else {
1117 // 7ci. If O is not undefined, convert the property named P of object O from an accessor property to a
1118 // data property. Preserve the existing values of the converted property’s [[Configurable]] and
1119 // [[Enumerable]] attributes and set the rest of the property’s attributes to their default values.
1120 }
1121 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
1122 } else if (current.IsDataDescriptor() && desc.IsDataDescriptor()) {
1123 // 8a. If the [[Configurable]] field of current is false, then
1124 if (!current.IsConfigurable()) {
1125 // 8a i. Return false, if the [[Writable]] field of current is false and the [[Writable]] field of Desc
1126 // is true.
1127 if (!current.IsWritable() && desc.HasWritable() && desc.IsWritable()) {
1128 return false;
1129 }
1130 // 8a ii. If the [[Writable]] field of current is false, then
1131 if (!current.IsWritable()) {
1132 if (desc.HasValue() && !JSTaggedValue::SameValue(current.GetValue(), desc.GetValue())) {
1133 return false;
1134 }
1135 }
1136 }
1137 // 8b. Else the [[Configurable]] field of current is true, so any change is acceptable.
1138 } else { // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true,
1139 // 9a. If the [[Configurable]] field of current is false, then
1140 if (!current.IsConfigurable()) {
1141 // i. Return false, if the [[Set]] field of Desc is present and SameValue(Desc.[[Set]], current.[[Set]])
1142 // is false.
1143 if (desc.HasSetter() && !JSTaggedValue::SameValue(current.GetSetter(), desc.GetSetter())) {
1144 return false;
1145 }
1146 // ii. Return false, if the [[Get]] field of Desc is present and SameValue(Desc.[[Get]],
1147 // current.[[Get]]) is false.
1148 if (desc.HasGetter() && !JSTaggedValue::SameValue(current.GetGetter(), desc.GetGetter())) {
1149 return false;
1150 }
1151 }
1152 }
1153
1154 if (op->HasHolder()) {
1155 // 10. If O is not undefined, then
1156 // a. For each field of Desc that is present, set the corresponding attribute of the property named P of object
1157 // O to the value of the field.
1158 return op->WriteDataPropertyInHolder(desc);
1159 }
1160 return true;
1161 }
1162
1163 // 9.1.6.2 IsCompatiblePropertyDescriptor (Extensible, Desc, Current)
IsCompatiblePropertyDescriptor(bool extensible,const PropertyDescriptor & desc,const PropertyDescriptor & current)1164 bool JSObject::IsCompatiblePropertyDescriptor(bool extensible, const PropertyDescriptor &desc,
1165 const PropertyDescriptor ¤t)
1166 {
1167 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined, Extensible, Desc, Current).
1168 ObjectOperator op;
1169 return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current);
1170 }
1171
GetPrototype(const JSHandle<JSObject> & obj)1172 JSTaggedValue JSObject::GetPrototype(const JSHandle<JSObject> &obj)
1173 {
1174 JSHClass *hclass = obj->GetJSHClass();
1175 return hclass->GetPrototype();
1176 }
1177
SetPrototype(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & proto)1178 bool JSObject::SetPrototype(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &proto)
1179 {
1180 ASSERT_PRINT(proto->IsECMAObject() || proto->IsNull(), "proto must be object or null");
1181 JSTaggedValue current = JSObject::GetPrototype(obj);
1182 if (current == proto.GetTaggedValue()) {
1183 return true;
1184 }
1185 if (!obj->IsExtensible()) {
1186 return false;
1187 }
1188 bool done = false;
1189 JSMutableHandle<JSTaggedValue> tempProtoHandle(thread, proto.GetTaggedValue());
1190 while (!done) {
1191 if (tempProtoHandle->IsNull() || !tempProtoHandle->IsECMAObject()) {
1192 done = true;
1193 } else if (JSTaggedValue::SameValue(tempProtoHandle.GetTaggedValue(), obj.GetTaggedValue())) {
1194 return false;
1195 } else {
1196 if (tempProtoHandle->IsJSProxy()) {
1197 break;
1198 }
1199 tempProtoHandle.Update(JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(tempProtoHandle)));
1200 }
1201 }
1202 // map transition
1203 JSHandle<JSHClass> hclass(thread, obj->GetJSHClass());
1204 JSHandle<JSHClass> newClass = JSHClass::TransitionProto(thread, hclass, proto);
1205 JSHClass::NotifyHclassChanged(thread, hclass, newClass);
1206 obj->SynchronizedSetClass(*newClass);
1207 thread->NotifyStableArrayElementsGuardians(obj, StableArrayChangeKind::PROTO);
1208 return true;
1209 }
1210
GetCtorFromPrototype(JSThread * thread,JSTaggedValue prototype)1211 JSTaggedValue JSObject::GetCtorFromPrototype(JSThread *thread, JSTaggedValue prototype)
1212 {
1213 if (!prototype.IsJSObject()) {
1214 return JSTaggedValue::Undefined();
1215 }
1216 JSHandle<JSTaggedValue> object(thread, prototype);
1217 JSHandle<JSTaggedValue> ctorKey = thread->GlobalConstants()->GetHandledConstructorString();
1218 JSHandle<JSTaggedValue> ctorObj(JSObject::GetProperty(thread, object, ctorKey).GetValue());
1219 if (thread->HasPendingException()) {
1220 thread->ClearException();
1221 return JSTaggedValue::Undefined();
1222 }
1223 return ctorObj.GetTaggedValue();
1224 }
1225
HasProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key)1226 bool JSObject::HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key)
1227 {
1228 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1229 JSHandle<JSTaggedValue> objValue(obj);
1230 ObjectOperator op(thread, objValue, key);
1231
1232 JSHandle<JSTaggedValue> holder = op.GetHolder();
1233 if (holder->IsJSProxy()) {
1234 return JSProxy::HasProperty(thread, JSHandle<JSProxy>::Cast(holder), key);
1235 }
1236
1237 return op.IsFound();
1238 }
1239
HasProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index)1240 bool JSObject::HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index)
1241 {
1242 JSHandle<JSTaggedValue> objValue(obj);
1243 ObjectOperator op(thread, objValue, index);
1244
1245 JSHandle<JSTaggedValue> holder = op.GetHolder();
1246 if (holder->IsJSProxy()) {
1247 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(index));
1248 return JSProxy::HasProperty(thread, JSHandle<JSProxy>::Cast(holder), key);
1249 }
1250
1251 return op.IsFound();
1252 }
1253
PreventExtensions(JSThread * thread,const JSHandle<JSObject> & obj)1254 bool JSObject::PreventExtensions(JSThread *thread, const JSHandle<JSObject> &obj)
1255 {
1256 if (obj->IsExtensible()) {
1257 JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
1258 JSHandle<JSHClass> newHclass = JSHClass::TransitionExtension(thread, jshclass);
1259 obj->SynchronizedSetClass(*newHclass);
1260 }
1261
1262 return true;
1263 }
1264
1265 // 9.1.12 [[OwnPropertyKeys]] ( )
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSObject> & obj)1266 JSHandle<TaggedArray> JSObject::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj)
1267 {
1268 uint32_t numOfElements = obj->GetNumberOfElements();
1269 uint32_t keyLen = numOfElements + obj->GetNumberOfKeys();
1270
1271 JSHandle<TaggedArray> keyArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(keyLen);
1272
1273 if (numOfElements > 0) {
1274 GetAllElementKeys(thread, obj, 0, keyArray);
1275 }
1276 GetAllKeys(thread, obj, static_cast<int32_t>(numOfElements), keyArray);
1277 return keyArray;
1278 }
1279
GetAllPropertyKeys(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t filter)1280 JSHandle<TaggedArray> JSObject::GetAllPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t filter)
1281 {
1282 JSMutableHandle<JSObject> currentObj(thread, obj);
1283 JSMutableHandle<JSTaggedValue> currentObjValue(thread, currentObj);
1284
1285 uint32_t curObjNumberOfElements = currentObj->GetNumberOfElements();
1286 uint32_t curObjNumberOfKeys = currentObj->GetNumberOfKeys();
1287 uint32_t curObjectKeysLength = curObjNumberOfElements + curObjNumberOfKeys;
1288 uint32_t retArrayLength = curObjectKeysLength;
1289 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1290 JSMutableHandle<TaggedArray> retArray(thread, factory->NewTaggedArray(retArrayLength));
1291 uint32_t retArrayEffectivelength = 0;
1292
1293 do {
1294 curObjNumberOfElements = currentObj->GetNumberOfElements();
1295 curObjNumberOfKeys = currentObj->GetNumberOfKeys();
1296 curObjectKeysLength = curObjNumberOfElements + curObjNumberOfKeys;
1297 uint32_t minRequireLength = curObjectKeysLength + retArrayEffectivelength;
1298 if (retArrayLength < minRequireLength) {
1299 // expand retArray
1300 retArray.Update(factory->NewAndCopyTaggedArray(retArray, minRequireLength, retArrayLength));
1301 retArrayLength = minRequireLength;
1302 }
1303
1304 GetAllElementKeysByFilter(thread, currentObj, retArray, retArrayEffectivelength, filter);
1305
1306 GetAllKeysByFilter(thread, currentObj, retArrayEffectivelength, retArray, filter);
1307 bool isInculdePrototypes = (filter & NATIVE_KEY_INCLUDE_PROTOTYPES);
1308 if (!isInculdePrototypes) {
1309 break;
1310 }
1311 currentObj.Update(GetPrototype(currentObj));
1312 currentObjValue.Update(currentObj);
1313 } while (currentObjValue->IsHeapObject());
1314
1315 JSMutableHandle<JSTaggedValue> element(thread, JSTaggedValue::Undefined());
1316 if (filter & NATIVE_KEY_NUMBERS_TO_STRINGS) {
1317 for (uint32_t i = 0; i < retArrayEffectivelength; i++) {
1318 element.Update(retArray->Get(i));
1319 if (element->IsNumber()) {
1320 retArray->Set(thread, i, base::NumberHelper::NumberToString(thread,
1321 JSTaggedValue(element->GetNumber())));
1322 }
1323 }
1324 }
1325 uint32_t elementIndex = 0;
1326 while ((filter & NATIVE_KEY_SKIP_STRINGS) && (retArrayEffectivelength > 0) &&
1327 (elementIndex < retArrayEffectivelength)) {
1328 if (retArray->Get(elementIndex).IsString()) {
1329 TaggedArray::RemoveElementByIndex(thread, retArray, elementIndex, retArrayEffectivelength);
1330 retArrayEffectivelength--;
1331 } else {
1332 elementIndex++;
1333 }
1334 }
1335 retArray->Trim(thread, retArrayEffectivelength);
1336 return retArray;
1337 }
1338
GetOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSObject> & obj)1339 JSHandle<TaggedArray> JSObject::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj)
1340 {
1341 uint32_t numOfElements = obj->GetNumberOfElements();
1342 uint32_t keyLen = numOfElements + obj->GetNumberOfKeys();
1343
1344 JSHandle<TaggedArray> keyArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(keyLen);
1345
1346 if (numOfElements > 0) {
1347 GetEnumElementKeys(thread, obj, 0, keyArray);
1348 }
1349 GetAllEnumKeys(thread, obj, static_cast<int32_t>(numOfElements), keyArray);
1350 return keyArray;
1351 }
1352
ObjectCreate(JSThread * thread,const JSHandle<JSObject> & proto)1353 JSHandle<JSObject> JSObject::ObjectCreate(JSThread *thread, const JSHandle<JSObject> &proto)
1354 {
1355 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1356 JSHandle<JSFunction> constructor(env->GetObjectFunction());
1357 JSHandle<JSObject> objHandle = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(constructor);
1358 SetPrototype(thread, objHandle, JSHandle<JSTaggedValue>(proto));
1359 return objHandle;
1360 }
1361
1362 // 7.3.4 CreateDataProperty (O, P, V)
CreateDataProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1363 bool JSObject::CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1364 const JSHandle<JSTaggedValue> &value)
1365 {
1366 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1367 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1368 auto result = ObjectFastOperator::SetPropertyByValue<true>(thread, obj.GetTaggedValue(), key.GetTaggedValue(),
1369 value.GetTaggedValue());
1370 if (!result.IsHole()) {
1371 return !result.IsException();
1372 }
1373 PropertyDescriptor desc(thread, value, true, true, true);
1374 return JSTaggedValue::DefineOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key, desc);
1375 }
1376
CreateDataProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const JSHandle<JSTaggedValue> & value)1377 bool JSObject::CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1378 const JSHandle<JSTaggedValue> &value)
1379 {
1380 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1381 auto result =
1382 ObjectFastOperator::SetPropertyByIndex<true>(thread, obj.GetTaggedValue(), index, value.GetTaggedValue());
1383 if (!result.IsHole()) {
1384 return !result.IsException();
1385 }
1386 PropertyDescriptor desc(thread, value, true, true, true);
1387 return DefineOwnProperty(thread, obj, index, desc);
1388 }
1389
1390 // 7.3.5 CreateMethodProperty (O, P, V)
CreateDataPropertyOrThrow(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1391 bool JSObject::CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj,
1392 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value)
1393 {
1394 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1395 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1396
1397 bool success = CreateDataProperty(thread, obj, key, value);
1398 if (!success) {
1399 THROW_TYPE_ERROR_AND_RETURN(thread, "failed to create data property", success);
1400 }
1401 return success;
1402 }
1403
CreateDataPropertyOrThrow(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const JSHandle<JSTaggedValue> & value)1404 bool JSObject::CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1405 const JSHandle<JSTaggedValue> &value)
1406 {
1407 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1408
1409 bool success = CreateDataProperty(thread, obj, index, value);
1410 if (!success) {
1411 THROW_TYPE_ERROR_AND_RETURN(thread, "failed to create data property", success);
1412 }
1413 return success;
1414 }
1415 // 7.3.6 CreateDataPropertyOrThrow (O, P, V)
CreateMethodProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1416 bool JSObject::CreateMethodProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1417 const JSHandle<JSTaggedValue> &value)
1418 {
1419 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1420 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1421
1422 PropertyDescriptor desc(thread, value, true, false, true);
1423 return DefineOwnProperty(thread, obj, key, desc);
1424 }
1425
1426 // 7.3.9 GetMethod (O, P)
GetMethod(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1427 JSHandle<JSTaggedValue> JSObject::GetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1428 const JSHandle<JSTaggedValue> &key)
1429 {
1430 JSHandle<JSTaggedValue> func = JSTaggedValue::GetProperty(thread, obj, key).GetValue();
1431 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1432 if (func->IsUndefined() || func->IsNull()) {
1433 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
1434 }
1435
1436 if (!func->IsCallable()) {
1437 THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not Callable", func);
1438 }
1439 return func;
1440 }
1441
1442 // 7.3.14 SetIntegrityLevel (O, level)
SetIntegrityLevel(JSThread * thread,const JSHandle<JSObject> & obj,IntegrityLevel level)1443 bool JSObject::SetIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level)
1444 {
1445 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1446 ASSERT_PRINT((level == IntegrityLevel::SEALED || level == IntegrityLevel::FROZEN),
1447 "level is not a valid IntegrityLevel");
1448
1449 bool status = JSTaggedValue::PreventExtensions(thread, JSHandle<JSTaggedValue>(obj));
1450 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1451 if (!status) {
1452 return false;
1453 }
1454
1455 JSHandle<TaggedArray> jshandleKeys =
1456 JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>(obj));
1457 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1458 PropertyDescriptor descNoConf(thread);
1459 descNoConf.SetConfigurable(false);
1460 PropertyDescriptor descNoConfWrite(thread);
1461 descNoConfWrite.SetWritable(false);
1462 descNoConfWrite.SetConfigurable(false);
1463
1464 if (level == IntegrityLevel::SEALED) {
1465 uint32_t length = jshandleKeys->GetLength();
1466 if (length == 0) {
1467 return true;
1468 }
1469 auto key = jshandleKeys->Get(0);
1470 JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1471 for (uint32_t i = 0; i < length; i++) {
1472 auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1473 handleKey.Update(taggedKey);
1474 [[maybe_unused]] bool success =
1475 JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(obj), handleKey, descNoConf);
1476 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1477 }
1478 } else {
1479 uint32_t length = jshandleKeys->GetLength();
1480 if (length == 0) {
1481 return true;
1482 }
1483 auto key = jshandleKeys->Get(0);
1484 JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1485 for (uint32_t i = 0; i < length; i++) {
1486 auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1487 handleKey.Update(taggedKey);
1488 PropertyDescriptor currentDesc(thread);
1489 bool curDescStatus =
1490 JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), handleKey, currentDesc);
1491 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1492 if (curDescStatus) {
1493 PropertyDescriptor desc = currentDesc.IsAccessorDescriptor() ? descNoConf : descNoConfWrite;
1494 [[maybe_unused]] bool success =
1495 JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(obj), handleKey, desc);
1496 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1497 }
1498 }
1499 }
1500 return true;
1501 }
1502
1503 // 7.3.15 TestIntegrityLevel (O, level)
TestIntegrityLevel(JSThread * thread,const JSHandle<JSObject> & obj,IntegrityLevel level)1504 bool JSObject::TestIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level)
1505 {
1506 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1507 ASSERT_PRINT((level == IntegrityLevel::SEALED || level == IntegrityLevel::FROZEN),
1508 "level is not a valid IntegrityLevel");
1509
1510 bool status = JSHandle<JSTaggedValue>(obj)->IsExtensible(thread);
1511 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1512 if (status) {
1513 return false;
1514 }
1515
1516 JSHandle<TaggedArray> jshandleKeys =
1517 JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>(obj));
1518 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1519 uint32_t length = jshandleKeys->GetLength();
1520 if (length == 0) {
1521 return true;
1522 }
1523 auto key = jshandleKeys->Get(0);
1524 JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1525 for (uint32_t i = 0; i < length; i++) {
1526 auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1527 handleKey.Update(taggedKey);
1528 PropertyDescriptor currentDesc(thread);
1529 bool curDescStatus =
1530 JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), handleKey, currentDesc);
1531 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1532 if (curDescStatus) {
1533 if (currentDesc.IsConfigurable()) {
1534 return false;
1535 }
1536 if (level == IntegrityLevel::FROZEN &&
1537 currentDesc.IsDataDescriptor() && currentDesc.IsWritable()) {
1538 return false;
1539 }
1540 }
1541 }
1542 return true;
1543 }
1544
1545 // 7.3.21 EnumerableOwnNames (O)
EnumerableOwnNames(JSThread * thread,const JSHandle<JSObject> & obj)1546 JSHandle<TaggedArray> JSObject::EnumerableOwnNames(JSThread *thread, const JSHandle<JSObject> &obj)
1547 {
1548 ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
1549 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1550 JSHandle<JSTaggedValue> tagObj(obj);
1551 // fast mode
1552 if (tagObj->IsJSObject() && !tagObj->IsTypedArray() && !tagObj->IsModuleNamespace()) {
1553 uint32_t copyLengthOfKeys = 0;
1554 uint32_t copyLengthOfElements = 0;
1555 auto keyElementPair = GetOwnEnumerableNamesInFastMode(thread, obj, ©LengthOfKeys, ©LengthOfElements);
1556 JSHandle<TaggedArray> keyArray = keyElementPair.first;
1557 JSHandle<TaggedArray> elementArray = keyElementPair.second;
1558 JSHandle<TaggedArray> keys;
1559 if (copyLengthOfKeys != 0 && copyLengthOfElements != 0) {
1560 keys = TaggedArray::AppendSkipHole(thread, elementArray, keyArray, copyLengthOfKeys + copyLengthOfElements);
1561 } else if (copyLengthOfKeys != 0) {
1562 keys = factory->CopyArray(keyArray, copyLengthOfKeys, copyLengthOfKeys);
1563 } else if (copyLengthOfElements != 0) {
1564 keys = factory->CopyArray(elementArray, copyLengthOfElements, copyLengthOfElements);
1565 } else {
1566 keys = factory->EmptyArray();
1567 }
1568 return keys;
1569 }
1570
1571 uint32_t copyLength = 0;
1572 JSHandle<TaggedArray> keys = JSTaggedValue::GetOwnPropertyKeys(thread, tagObj);
1573 RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1574 uint32_t length = keys->GetLength();
1575
1576 JSHandle<TaggedArray> names = factory->NewTaggedArray(length);
1577 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
1578 for (uint32_t i = 0; i < length; i++) {
1579 keyHandle.Update(keys->Get(i));
1580 if (keyHandle->IsString()) {
1581 PropertyDescriptor desc(thread);
1582 bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj),
1583 keyHandle, desc);
1584 RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1585
1586 if (status && desc.IsEnumerable()) {
1587 names->Set(thread, copyLength, keyHandle);
1588 copyLength++;
1589 }
1590 }
1591 }
1592
1593 return factory->CopyArray(names, length, copyLength);
1594 }
1595
EnumerableOwnPropertyNamesHelper(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<TaggedArray> & arr,JSHandle<TaggedArray> & prop,uint32_t & index,bool & fastMode,PropertyKind kind)1596 void JSObject::EnumerableOwnPropertyNamesHelper(JSThread *thread, const JSHandle<JSObject> &obj,
1597 const JSHandle<TaggedArray> &arr, JSHandle<TaggedArray> &prop, uint32_t &index, bool &fastMode, PropertyKind kind)
1598 {
1599 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1600 JSHandle<JSHClass> objClass(thread, obj->GetJSHClass());
1601 uint32_t length = arr->GetLength();
1602 for (uint32_t i = 0; i < length; i++) {
1603 key.Update(arr->Get(thread, i));
1604 if (!JSTaggedValue::IsPropertyKey(key)) {
1605 break;
1606 }
1607 JSTaggedValue value = JSTaggedValue::Hole();
1608 if (fastMode) {
1609 value = ObjectFastOperator::GetPropertyByValue<true>(thread, obj.GetTaggedValue(), key.GetTaggedValue());
1610 RETURN_IF_ABRUPT_COMPLETION(thread);
1611 }
1612 if (value.IsHole()) {
1613 PropertyDescriptor desc(thread);
1614 bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), key, desc);
1615 RETURN_IF_ABRUPT_COMPLETION(thread);
1616 if (!status || !desc.IsEnumerable()) {
1617 continue;
1618 }
1619 if (desc.HasValue()) {
1620 value = desc.GetValue().GetTaggedValue();
1621 } else {
1622 OperationResult opResult = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key);
1623 RETURN_IF_ABRUPT_COMPLETION(thread);
1624 value = opResult.GetValue().GetTaggedValue();
1625 }
1626 }
1627 index = SetValuesOrEntries(thread, prop, index, key, JSHandle<JSTaggedValue>(thread, value), kind);
1628 fastMode = fastMode ? CheckHClassHit(obj, objClass) : fastMode;
1629 }
1630 }
1631
EnumerableOwnPropertyNames(JSThread * thread,const JSHandle<JSObject> & obj,PropertyKind kind)1632 JSHandle<TaggedArray> JSObject::EnumerableOwnPropertyNames(JSThread *thread, const JSHandle<JSObject> &obj,
1633 PropertyKind kind)
1634 {
1635 // 1. Assert: Type(O) is Object.
1636 ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
1637
1638 // 2. Let ownKeys be ? O.[[OwnPropertyKeys]]().
1639 JSHandle<JSTaggedValue> tagObj(obj);
1640 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1641 if (tagObj->IsJSObject() && !tagObj->IsJSProxy() && !tagObj->IsTypedArray() && !tagObj->IsModuleNamespace()) {
1642 uint32_t copyLengthOfKeys = 0;
1643 uint32_t copyLengthOfElements = 0;
1644 uint32_t index = 0;
1645 bool fastMode = true;
1646 auto keyElementPair = GetOwnEnumerableNamesInFastMode(thread, obj, ©LengthOfKeys, ©LengthOfElements);
1647 JSHandle<TaggedArray> keyArray = keyElementPair.first;
1648 JSHandle<TaggedArray> elementArray = keyElementPair.second;
1649 JSHandle<TaggedArray> properties = factory->NewTaggedArray(copyLengthOfKeys + copyLengthOfElements);
1650 if (copyLengthOfElements != 0) {
1651 EnumerableOwnPropertyNamesHelper(thread, obj, elementArray, properties, index, fastMode, kind);
1652 }
1653 if (copyLengthOfKeys != 0) {
1654 EnumerableOwnPropertyNamesHelper(thread, obj, keyArray, properties, index, fastMode, kind);
1655 }
1656 if (UNLIKELY(!fastMode && index < copyLengthOfKeys + copyLengthOfElements)) {
1657 properties->Trim(thread, index);
1658 }
1659 return properties;
1660 }
1661
1662 JSHandle<TaggedArray> ownKeys = JSTaggedValue::GetOwnPropertyKeys(thread, tagObj);
1663 RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1664
1665 // 3. Let properties be a new empty List.
1666 uint32_t length = ownKeys->GetLength();
1667 JSHandle<TaggedArray> properties = factory->NewTaggedArray(length);
1668
1669 // 4. For each element key of ownKeys, do
1670 // a. If Type(key) is String, then
1671 // i. Let desc be ? O.[[GetOwnProperty]](key).
1672 // ii. If desc is not undefined and desc.[[Enumerable]] is true, then
1673 // 1. If kind is key, append key to properties.
1674 // 2. Else,
1675 // a. Let value be ? Get(O, key).
1676 // b. If kind is value, append value to properties.
1677 // c. Else,
1678 // i. Assert: kind is key+value.
1679 // ii. Let entry be ! CreateArrayFromList(« key, value »).
1680 // iii. Append entry to properties.
1681 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1682 uint32_t index = 0;
1683 for (uint32_t i = 0; i < length; i++) {
1684 key.Update(ownKeys->Get(thread, i));
1685 if (key->IsString()) {
1686 PropertyDescriptor desc(thread);
1687 bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj),
1688 key, desc);
1689 RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1690 if (status && desc.IsEnumerable()) {
1691 if (kind == PropertyKind::KEY) {
1692 properties->Set(thread, index++, key);
1693 } else {
1694 OperationResult result =
1695 JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key);
1696 RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1697 JSHandle<JSTaggedValue> value = result.GetValue();
1698 index = SetValuesOrEntries(thread, properties, index, key, value, kind);
1699 }
1700 }
1701 }
1702 }
1703
1704 if (UNLIKELY(index < length)) {
1705 properties->Trim(thread, index);
1706 }
1707 // 5. Return properties.
1708 return properties;
1709 }
1710
GetFunctionRealm(JSThread * thread,const JSHandle<JSTaggedValue> & object)1711 JSHandle<GlobalEnv> JSObject::GetFunctionRealm(JSThread *thread, const JSHandle<JSTaggedValue> &object)
1712 {
1713 // 1. Assert: obj is a callable object.
1714 ASSERT(object->IsCallable());
1715 // 2. If obj has a [[Realm]] internal slot, then return obj’s [[Realm]] internal slot.
1716 // 3. If obj is a Bound Function exotic object, then
1717 if (object->IsBoundFunction()) {
1718 // a. Let target be obj’s [[BoundTargetFunction]] internal slot.
1719 JSHandle<JSTaggedValue> target(thread, JSHandle<JSBoundFunction>(object)->GetBoundTarget());
1720 // b. Return GetFunctionRealm(target).
1721 return GetFunctionRealm(thread, target);
1722 }
1723 // 4. If obj is a Proxy exotic object, then
1724 if (object->IsJSProxy()) {
1725 // a. If the value of the [[ProxyHandler]] internal slot of obj is null, throw a TypeError exception.
1726 if (JSHandle<JSProxy>(object)->GetHandler().IsNull()) {
1727 THROW_TYPE_ERROR_AND_RETURN(thread, "JSObject::GetFunctionRealm: handler is null",
1728 JSHandle<GlobalEnv>(thread, JSTaggedValue::Exception()));
1729 }
1730 // b. Let proxyTarget be the value of obj’s [[ProxyTarget]] internal slot.
1731 JSHandle<JSTaggedValue> proxyTarget(thread, JSHandle<JSProxy>(object)->GetTarget());
1732 return GetFunctionRealm(thread, proxyTarget);
1733 }
1734 JSTaggedValue maybeGlobalEnv = JSHandle<JSFunction>(object)->GetLexicalEnv();
1735 while (!maybeGlobalEnv.IsJSGlobalEnv()) {
1736 if (maybeGlobalEnv.IsUndefined()) {
1737 return thread->GetEcmaVM()->GetGlobalEnv();
1738 }
1739 maybeGlobalEnv = LexicalEnv::Cast(maybeGlobalEnv.GetTaggedObject())->GetParentEnv();
1740 }
1741 return JSHandle<GlobalEnv>(thread, maybeGlobalEnv);
1742 }
1743
InstanceOf(JSThread * thread,const JSHandle<JSTaggedValue> & object,const JSHandle<JSTaggedValue> & target)1744 bool JSObject::InstanceOf(JSThread *thread, const JSHandle<JSTaggedValue> &object,
1745 const JSHandle<JSTaggedValue> &target)
1746 {
1747 // 1. If Type(target) is not Object, throw a TypeError exception.
1748 if (!target->IsECMAObject()) {
1749 THROW_TYPE_ERROR_AND_RETURN(thread, "InstanceOf error when type of target is not Object", false);
1750 }
1751
1752 EcmaVM *vm = thread->GetEcmaVM();
1753 // 2. Let instOfHandler be GetMethod(target, @@hasInstance).
1754 JSHandle<JSTaggedValue> instOfHandler = GetMethod(thread, target, vm->GetGlobalEnv()->GetHasInstanceSymbol());
1755
1756 // 3. ReturnIfAbrupt(instOfHandler).
1757 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1758
1759 // 4. If instOfHandler is not undefined, then
1760 if (!instOfHandler->IsUndefined()) {
1761 // a. Return ! ToBoolean(? Call(instOfHandler, target, «object»)).
1762 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1763 EcmaRuntimeCallInfo *info =
1764 EcmaInterpreter::NewRuntimeCallInfo(thread, instOfHandler, target, undefined, 1);
1765 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1766 info->SetCallArg(object.GetTaggedValue());
1767 JSTaggedValue tagged = JSFunction::Call(info);
1768 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1769 return tagged.ToBoolean();
1770 }
1771
1772 // 5. If IsCallable(target) is false, throw a TypeError exception.
1773 if (!target->IsCallable()) {
1774 THROW_TYPE_ERROR_AND_RETURN(thread, "InstanceOf error when target is not Callable", false);
1775 }
1776
1777 // 6. Return ? OrdinaryHasInstance(target, object).
1778 return JSFunction::OrdinaryHasInstance(thread, target, object);
1779 }
1780
1781 // ecma6.0 6.2.4.4
FromPropertyDescriptor(JSThread * thread,const PropertyDescriptor & desc)1782 JSHandle<JSTaggedValue> JSObject::FromPropertyDescriptor(JSThread *thread, const PropertyDescriptor &desc)
1783 {
1784 // 1. If Desc is undefined, return undefined
1785 if (desc.IsEmpty()) {
1786 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
1787 }
1788
1789 // 2. Let obj be ObjectCreate(%ObjectPrototype%).
1790 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1791 JSHandle<JSFunction> objFunc(env->GetObjectFunction());
1792 JSHandle<JSObject> objHandle = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(objFunc);
1793
1794 auto globalConst = thread->GlobalConstants();
1795 // 4. If Desc has a [[Value]] field, then Perform CreateDataProperty(obj, "value", Desc.[[Value]]).
1796 if (desc.HasValue()) {
1797 JSHandle<JSTaggedValue> valueStr = globalConst->GetHandledValueString();
1798 bool success = CreateDataProperty(thread, objHandle, valueStr, desc.GetValue());
1799 RASSERT_PRINT(success, "CreateDataProperty must be success");
1800 }
1801 // 5. If Desc has a [[Writable]] field, then Perform CreateDataProperty(obj, "writable", Desc.[[Writable]]).
1802 if (desc.HasWritable()) {
1803 JSHandle<JSTaggedValue> writableStr = globalConst->GetHandledWritableString();
1804 JSHandle<JSTaggedValue> writable(thread, JSTaggedValue(desc.IsWritable()));
1805 [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, writableStr, writable);
1806 ASSERT_PRINT(success, "CreateDataProperty must be success");
1807 }
1808 // 6. If Desc has a [[Get]] field, then Perform CreateDataProperty(obj, "get", Desc.[[Get]]).
1809 if (desc.HasGetter()) {
1810 JSHandle<JSTaggedValue> getStr = globalConst->GetHandledGetString();
1811 bool success = CreateDataProperty(thread, objHandle, getStr, desc.GetGetter());
1812 RASSERT_PRINT(success, "CreateDataProperty must be success");
1813 }
1814 // 7. If Desc has a [[Set]] field, then Perform CreateDataProperty(obj, "set", Desc.[[Set]])
1815 if (desc.HasSetter()) {
1816 JSHandle<JSTaggedValue> setStr = globalConst->GetHandledSetString();
1817 bool success = CreateDataProperty(thread, objHandle, setStr, desc.GetSetter());
1818 RASSERT_PRINT(success, "CreateDataProperty must be success");
1819 }
1820 // 8. If Desc has an [[Enumerable]] field, then Perform CreateDataProperty(obj, "enumerable",
1821 // Desc.[[Enumerable]]).
1822 if (desc.HasEnumerable()) {
1823 JSHandle<JSTaggedValue> enumerableStr = globalConst->GetHandledEnumerableString();
1824 JSHandle<JSTaggedValue> enumerable(thread, JSTaggedValue(desc.IsEnumerable()));
1825 [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, enumerableStr, enumerable);
1826 ASSERT_PRINT(success, "CreateDataProperty must be success");
1827 }
1828 // 9. If Desc has a [[Configurable]] field, then Perform CreateDataProperty(obj , "configurable",
1829 // Desc.[[Configurable]]).
1830 if (desc.HasConfigurable()) {
1831 JSHandle<JSTaggedValue> configurableStr = globalConst->GetHandledConfigurableString();
1832 JSHandle<JSTaggedValue> configurable(thread, JSTaggedValue(desc.IsConfigurable()));
1833 [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, configurableStr, configurable);
1834 ASSERT_PRINT(success, "CreateDataProperty must be success");
1835 }
1836 return JSHandle<JSTaggedValue>(objHandle);
1837 }
1838
ToPropertyDescriptorFast(JSThread * thread,const JSHandle<JSTaggedValue> & obj,PropertyDescriptor & desc)1839 bool JSObject::ToPropertyDescriptorFast(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc)
1840 {
1841 auto *hclass = obj->GetTaggedObject()->GetClass();
1842 JSType jsType = hclass->GetObjectType();
1843 if (jsType != JSType::JS_OBJECT) {
1844 return false;
1845 }
1846 if (hclass->IsDictionaryMode()) {
1847 return false;
1848 }
1849 auto env = thread->GetEcmaVM()->GetGlobalEnv();
1850 auto globalConst = thread->GlobalConstants();
1851 if (hclass->GetPrototype() != env->GetObjectFunctionPrototype().GetTaggedValue()) {
1852 return false;
1853 }
1854 if (JSObject::Cast(hclass->GetPrototype().GetTaggedObject())->GetClass() !=
1855 env->GetObjectFunctionPrototypeClass().GetObject<JSHClass>()) {
1856 return false;
1857 }
1858 LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
1859 uint32_t propsNumber = hclass->NumberOfProps();
1860 for (uint32_t i = 0; i < propsNumber; i++) {
1861 auto attr = layoutInfo->GetAttr(i);
1862 if (attr.IsAccessor()) {
1863 return false;
1864 }
1865 auto key = layoutInfo->GetKey(i);
1866 auto value = JSObject::Cast(obj->GetTaggedObject())->GetProperty(hclass, attr);
1867 if (key == globalConst->GetEnumerableString()) {
1868 bool enumerable = value.ToBoolean();
1869 desc.SetEnumerable(enumerable);
1870 } else if (key == globalConst->GetConfigurableString()) {
1871 bool configurable = value.ToBoolean();
1872 desc.SetConfigurable(configurable);
1873 } else if (key == globalConst->GetValueString()) {
1874 auto handleValue = JSHandle<JSTaggedValue>(thread, value);
1875 desc.SetValue(handleValue);
1876 } else if (key == globalConst->GetWritableString()) {
1877 bool writable = value.ToBoolean();
1878 desc.SetWritable(writable);
1879 } else if (key == globalConst->GetGetString()) {
1880 if (!value.IsCallable()) {
1881 return false;
1882 }
1883 auto getter = JSHandle<JSTaggedValue>(thread, value);
1884 desc.SetGetter(getter);
1885 } else if (key == globalConst->GetSetString()) {
1886 if (!value.IsCallable()) {
1887 return false;
1888 }
1889 auto setter = JSHandle<JSTaggedValue>(thread, value);
1890 desc.SetSetter(setter);
1891 }
1892 }
1893
1894 if (desc.IsAccessorDescriptor()) {
1895 // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, throw a TypeError exception.
1896 if (desc.HasValue() || desc.HasWritable()) {
1897 THROW_TYPE_ERROR_AND_RETURN(thread, "either Value or Writable is present", true);
1898 }
1899 }
1900 return true;
1901 }
1902
1903 // ecma6.0 6.2.4.5 ToPropertyDescriptor ( Obj )
ToPropertyDescriptor(JSThread * thread,const JSHandle<JSTaggedValue> & obj,PropertyDescriptor & desc)1904 void JSObject::ToPropertyDescriptor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc)
1905 {
1906 if (!obj->IsECMAObject()) {
1907 // 2. If Type(Obj) is not Object, throw a TypeError exception.
1908 THROW_TYPE_ERROR(thread, "ToPropertyDescriptor error obj is not Object");
1909 }
1910
1911 if (ToPropertyDescriptorFast(thread, obj, desc)) {
1912 return;
1913 }
1914 auto globalConst = thread->GlobalConstants();
1915 // 3. Let desc be a new Property Descriptor that initially has no fields.
1916 // 4. Let hasEnumerable be HasProperty(Obj, "enumerable")
1917 {
1918 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetEnumerableString());
1919 if (op.IsFound()) {
1920 auto value = op.FastGetValue();
1921 bool enumerable = value->IsException() ? false : value->ToBoolean();
1922 desc.SetEnumerable(enumerable);
1923 }
1924 }
1925 // 7. Let hasConfigurable be HasProperty(Obj, "configurable").
1926 {
1927 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetConfigurableString());
1928 if (op.IsFound()) {
1929 auto value = op.FastGetValue();
1930 bool conf = value->IsException() ? false : value->ToBoolean();
1931 desc.SetConfigurable(conf);
1932 }
1933 }
1934 // 10. Let hasValue be HasProperty(Obj, "value").
1935 {
1936 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetValueString());
1937 if (op.IsFound()) {
1938 JSHandle<JSTaggedValue> prop = op.FastGetValue();
1939 desc.SetValue(prop);
1940 }
1941 }
1942 // 13. Let hasWritable be HasProperty(Obj, "writable").
1943 {
1944 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetWritableString());
1945 if (op.IsFound()) {
1946 auto value = op.FastGetValue();
1947 bool writable = value->IsException() ? false : value->ToBoolean();
1948 desc.SetWritable(writable);
1949 }
1950 }
1951 // 16. Let hasGet be HasProperty(Obj, "get").
1952 {
1953 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetGetString());
1954 if (op.IsFound()) {
1955 JSHandle<JSTaggedValue> getter = op.FastGetValue();
1956 if (!getter->IsCallable() && !getter->IsUndefined()) {
1957 THROW_TYPE_ERROR(thread, "getter not callable or undefined");
1958 }
1959 desc.SetGetter(getter);
1960 }
1961 }
1962
1963 // 19. Let hasSet be HasProperty(Obj, "set").
1964 {
1965 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetSetString());
1966 if (op.IsFound()) {
1967 JSHandle<JSTaggedValue> setter = op.FastGetValue();
1968 if (!setter->IsCallable() && !setter->IsUndefined()) {
1969 THROW_TYPE_ERROR(thread, "setter not callable or undefined");
1970 }
1971 desc.SetSetter(setter);
1972 }
1973 }
1974
1975 // 22. If either desc.[[Get]] or desc.[[Set]] is present, then
1976 if (desc.IsAccessorDescriptor()) {
1977 // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, throw a TypeError exception.
1978 if (desc.HasValue() || desc.HasWritable()) {
1979 THROW_TYPE_ERROR(thread, "either desc.[[Value]] or desc.[[Writable]] is present");
1980 }
1981 }
1982 // 23. Return desc.
1983 }
1984
SpeciesConstructor(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & defaultConstructort)1985 JSHandle<JSTaggedValue> JSObject::SpeciesConstructor(JSThread *thread, const JSHandle<JSObject> &obj,
1986 const JSHandle<JSTaggedValue> &defaultConstructort)
1987 {
1988 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1989 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
1990 // Assert: Type(O) is Object.
1991 ASSERT_PRINT(obj->IsECMAObject(), "obj must be js object");
1992
1993 // Let C be Get(O, "constructor").
1994 JSHandle<JSTaggedValue> contructorKey = globalConst->GetHandledConstructorString();
1995 JSHandle<JSTaggedValue> objConstructor(JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(obj),
1996 contructorKey).GetValue());
1997 // ReturnIfAbrupt(C).
1998 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1999 // If C is undefined, return defaultConstructor.
2000 if (objConstructor->IsUndefined()) {
2001 return defaultConstructort;
2002 }
2003 // If Type(C) is not Object, throw a TypeError exception.
2004 if (!objConstructor->IsECMAObject()) {
2005 THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is not Object",
2006 JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
2007 }
2008 // Let S be Get(C, @@species).
2009 JSHandle<JSTaggedValue> speciesSymbol = env->GetSpeciesSymbol();
2010 JSHandle<JSTaggedValue> speciesConstructor(GetProperty(thread, objConstructor, speciesSymbol).GetValue());
2011 // ReturnIfAbrupt(S).
2012 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
2013 // If S is either undefined or null, return defaultConstructor.
2014 if (speciesConstructor->IsUndefined() || speciesConstructor->IsNull()) {
2015 return defaultConstructort;
2016 }
2017 // If IsConstructor(S) is true, return S.
2018 if (speciesConstructor->IsConstructor()) {
2019 return speciesConstructor;
2020 }
2021 // Throw a TypeError exception.
2022 THROW_TYPE_ERROR_AND_RETURN(thread, "Is not Constructor",
2023 JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
2024 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception());
2025 }
2026
2027 // 6.2.4.6 CompletePropertyDescriptor ( Desc )
CompletePropertyDescriptor(const JSThread * thread,PropertyDescriptor & desc)2028 void PropertyDescriptor::CompletePropertyDescriptor(const JSThread *thread, PropertyDescriptor &desc)
2029 {
2030 // 1. ReturnIfAbrupt(Desc).
2031 // 2. Assert: Desc is a Property Descriptor
2032 // 3. Let like be Record{[[Value]]: undefined, [[Writable]]: false, [[Get]]: undefined, [[Set]]: undefined,
2033 // [[Enumerable]]: false, [[Configurable]]: false}.
2034 // 4. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then
2035 if (!desc.IsAccessorDescriptor()) {
2036 // a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to like.[[Value]].
2037 // b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]] to like.[[Writable]].
2038 if (!desc.HasValue()) {
2039 desc.SetValue(JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
2040 }
2041 if (!desc.HasWritable()) {
2042 desc.SetWritable(false);
2043 }
2044 } else {
2045 // a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to like.[[Get]].
2046 // b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to like.[[Set]].
2047 // Default value of Get and Set is undefined.
2048 }
2049 // 6. If Desc does not have an [[Enumerable]] field, set Desc.[[Enumerable]] to like.[[Enumerable]].
2050 // 7. If Desc does not have a [[Configurable]] field, set Desc.[[Configurable]] to like.[[Configurable]].
2051 if (!desc.HasEnumerable()) {
2052 desc.SetEnumerable(false);
2053 }
2054 if (!desc.HasConfigurable()) {
2055 desc.SetConfigurable(false);
2056 }
2057 }
2058
2059 // 13.7.5.15 EnumerateObjectProperties ( O )
EnumerateObjectProperties(JSThread * thread,const JSHandle<JSTaggedValue> & obj)2060 JSHandle<JSForInIterator> JSObject::EnumerateObjectProperties(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
2061 {
2062 // 1. Return an Iterator object (25.1.1.2) whose next method iterates over all the String-valued keys of
2063 // enumerable properties of O. The Iterator object must inherit from %IteratorPrototype% (25.1.2). The
2064 // mechanics and order of enumerating the properties is not specified but must conform to the rules specified
2065 // below.
2066 JSHandle<JSTaggedValue> object;
2067 if (obj->IsString()) {
2068 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2069 object = JSHandle<JSTaggedValue>::Cast(JSPrimitiveRef::StringCreate(thread, obj, undefined));
2070 } else {
2071 object = JSTaggedValue::ToPrototypeOrObj(thread, obj);
2072 }
2073
2074 return thread->GetEcmaVM()->GetFactory()->NewJSForinIterator(object);
2075 }
2076
DefinePropertyByLiteral(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool useForClass)2077 void JSObject::DefinePropertyByLiteral(JSThread *thread, const JSHandle<JSObject> &obj,
2078 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
2079 bool useForClass)
2080 {
2081 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
2082 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2083 PropertyAttributes attr = useForClass ? PropertyAttributes::Default(true, false, true)
2084 : PropertyAttributes::Default();
2085
2086 if (value->IsAccessorData()) {
2087 attr.SetIsAccessor(true);
2088 }
2089
2090 uint32_t index = 0;
2091 if (UNLIKELY(JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
2092 AddElementInternal(thread, obj, index, value, attr);
2093 return;
2094 }
2095 LOG_ECMA(FATAL) << "this branch is unreachable";
2096 UNREACHABLE();
2097 }
2098
DefineSetter(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)2099 void JSObject::DefineSetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2100 const JSHandle<JSTaggedValue> &value)
2101 {
2102 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2103 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2104 ObjectOperator op(thread, obj, key, OperatorType::OWN);
2105 ASSERT(op.IsFound());
2106 op.DefineSetter(value);
2107 }
2108
DefineGetter(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)2109 void JSObject::DefineGetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2110 const JSHandle<JSTaggedValue> &value)
2111 {
2112 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2113 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2114 ObjectOperator op(thread, obj, key, OperatorType::OWN);
2115 ASSERT(op.IsFound());
2116 op.DefineGetter(value);
2117 }
2118
CreateObjectFromProperties(const JSThread * thread,const JSHandle<TaggedArray> & properties,JSTaggedValue ihcVal)2119 JSHandle<JSObject> JSObject::CreateObjectFromProperties(const JSThread *thread, const JSHandle<TaggedArray> &properties,
2120 JSTaggedValue ihcVal)
2121 {
2122 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2123 size_t length = properties->GetLength();
2124 uint32_t propsLen = 0;
2125 for (size_t i = 0; i < length; i += 2) { // 2: skip a pair of key and value
2126 if (properties->Get(i).IsHole()) {
2127 break;
2128 }
2129 propsLen++;
2130 }
2131 if (propsLen <= PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES) {
2132 JSHandle<JSObject> obj = factory->NewOldSpaceObjLiteralByHClass(properties, propsLen);
2133 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
2134 if (ihcVal.IsJSHClass()) {
2135 bool isSuccess = true;
2136 JSHClass *ihc = JSHClass::Cast(ihcVal.GetTaggedObject());
2137 JSHClass *oldHC = obj->GetJSHClass();
2138 ihc->SetPrototype(thread, oldHC->GetPrototype());
2139 obj->SetClass(ihc);
2140 for (size_t i = 0; i < propsLen; i++) {
2141 auto value = obj->ConvertValueWithRep(i, properties->Get(i * 2 + 1));
2142 if (!value.first) {
2143 isSuccess = false;
2144 break;
2145 }
2146 obj->SetPropertyInlinedPropsWithRep(thread, i, value.second);
2147 }
2148 if (isSuccess) {
2149 return obj;
2150 }
2151 // The layout representation of ihc is inaccurate and needs to be rolled back to the old HClass
2152 obj->SetClass(oldHC);
2153 }
2154 for (size_t i = 0; i < propsLen; i++) {
2155 // 2: literal contains a pair of key-value
2156 obj->SetPropertyInlinedProps(thread, i, properties->Get(i * 2 + 1));
2157 }
2158 return obj;
2159 } else {
2160 JSHandle<JSObject> obj = factory->NewEmptyJSObject();
2161 JSHClass::TransitionToDictionary(thread, obj);
2162
2163 JSMutableHandle<NameDictionary> dict(
2164 thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(propsLen)));
2165 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
2166 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
2167 for (size_t i = 0; i < propsLen; i++) {
2168 PropertyAttributes attr = PropertyAttributes::Default();
2169 // 2: literal contains a pair of key-value
2170 valueHandle.Update(properties->Get(i * 2 + 1));
2171 // 2: literal contains a pair of key-value
2172 keyHandle.Update(properties->Get(i * 2));
2173 JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
2174 dict.Update(newDict);
2175 }
2176 obj->SetProperties(thread, dict);
2177 return obj;
2178 }
2179 }
2180
AddAccessor(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<AccessorData> & value,PropertyAttributes attr)2181 void JSObject::AddAccessor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2182 const JSHandle<AccessorData> &value, PropertyAttributes attr)
2183 {
2184 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2185 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2186 ASSERT_PRINT(attr.IsAccessor(), "Attr is not AccessorData");
2187 ObjectOperator op(thread, obj, key, OperatorType::OWN);
2188 ASSERT(!op.IsFound());
2189 op.AddProperty(JSHandle<JSObject>::Cast(obj), JSHandle<JSTaggedValue>(value), attr);
2190 }
2191
UpdatePropertyInDictionary(const JSThread * thread,JSTaggedValue key,JSTaggedValue value)2192 bool JSObject::UpdatePropertyInDictionary(const JSThread *thread, JSTaggedValue key, JSTaggedValue value)
2193 {
2194 [[maybe_unused]] DisallowGarbageCollection noGc;
2195 NameDictionary *dict = NameDictionary::Cast(GetProperties().GetTaggedObject());
2196 int entry = dict->FindEntry(key);
2197 if (entry == -1) {
2198 return false;
2199 }
2200 dict->UpdateValue(thread, entry, value);
2201 return true;
2202 }
2203
2204 // The hash field may be a hash value, FunctionExtraInfo(JSNativePointer) or TaggedArray
SetHash(int32_t hash)2205 void ECMAObject::SetHash(int32_t hash)
2206 {
2207 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2208 JSTaggedValue value(hashField);
2209 if (value.IsHeapObject()) {
2210 JSThread *thread = this->GetJSThread();
2211 // Hash position reserve in advance.
2212 if (value.IsTaggedArray()) {
2213 TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2214 array->Set(thread, array->GetExtraLength() + HASH_INDEX, JSTaggedValue(hash));
2215 } else if (value.IsNativePointer()) { // FunctionExtraInfo
2216 JSHandle<TaggedArray> newArray =
2217 thread->GetEcmaVM()->GetFactory()->NewTaggedArray(RESOLVED_MAX_SIZE);
2218 newArray->SetExtraLength(0);
2219 newArray->Set(thread, HASH_INDEX, JSTaggedValue(hash));
2220 newArray->Set(thread, FUNCTION_EXTRA_INDEX, value);
2221 Barriers::SetObject<true>(thread, this, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2222 } else {
2223 LOG_ECMA(FATAL) << "this branch is unreachable";
2224 UNREACHABLE();
2225 }
2226 } else {
2227 Barriers::SetPrimitive<JSTaggedType>(this, HASH_OFFSET, JSTaggedValue(hash).GetRawData());
2228 }
2229 }
2230
GetHash() const2231 int32_t ECMAObject::GetHash() const
2232 {
2233 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2234 JSTaggedValue value(hashField);
2235 if (value.IsHeapObject()) {
2236 if (value.IsTaggedArray()) {
2237 TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2238 return array->Get(array->GetExtraLength() + HASH_INDEX).GetInt();
2239 } else {
2240 // Default is 0
2241 return 0;
2242 }
2243 }
2244 JSThread *thread = this->GetJSThread();
2245 JSHandle<JSTaggedValue> valueHandle(thread, value);
2246 return JSTaggedValue::ToInt32(thread, valueHandle);
2247 }
2248
HasHash() const2249 bool ECMAObject::HasHash() const
2250 {
2251 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2252 JSTaggedValue value(hashField);
2253 if (value.IsInt() && value.GetInt() == 0) {
2254 return false;
2255 }
2256 return true;
2257 }
2258
GetNativePointerField(int32_t index) const2259 void *ECMAObject::GetNativePointerField(int32_t index) const
2260 {
2261 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2262 JSTaggedValue value(hashField);
2263 if (value.IsTaggedArray()) {
2264 JSThread *thread = this->GetJSThread();
2265 JSHandle<TaggedArray> array(thread, value);
2266 if (static_cast<int32_t>(array->GetExtraLength()) > index) {
2267 JSHandle<JSNativePointer> pointer(thread, array->Get(index));
2268 return pointer->GetExternalPointer();
2269 }
2270 }
2271 return nullptr;
2272 }
2273
SetNativePointerField(int32_t index,void * nativePointer,const DeleteEntryPoint & callBack,void * data,size_t nativeBindingsize)2274 void ECMAObject::SetNativePointerField(int32_t index, void *nativePointer,
2275 const DeleteEntryPoint &callBack, void *data, size_t nativeBindingsize)
2276 {
2277 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2278 JSTaggedValue value(hashField);
2279 if (value.IsTaggedArray()) {
2280 JSThread *thread = this->GetJSThread();
2281 JSHandle<TaggedArray> array(thread, value);
2282 if (static_cast<int32_t>(array->GetExtraLength()) > index) {
2283 EcmaVM *vm = thread->GetEcmaVM();
2284 JSHandle<JSTaggedValue> current = JSHandle<JSTaggedValue>(thread, array->Get(thread, index));
2285 if (!current->IsHole() && nativePointer == nullptr) {
2286 // Try to remove native pointer if exists.
2287 vm->RemoveFromNativePointerList(*JSHandle<JSNativePointer>(current));
2288 array->Set(thread, index, JSTaggedValue::Hole());
2289 } else {
2290 JSHandle<JSNativePointer> pointer = vm->GetFactory()->NewJSNativePointer(
2291 nativePointer, callBack, data, false, nativeBindingsize);
2292 array->Set(thread, index, pointer.GetTaggedValue());
2293 }
2294 }
2295 }
2296 }
2297
GetNativePointerFieldCount() const2298 int32_t ECMAObject::GetNativePointerFieldCount() const
2299 {
2300 int32_t len = 0;
2301 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2302 JSTaggedValue value(hashField);
2303 if (value.IsTaggedArray()) {
2304 TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2305 len = static_cast<int32_t>(array->GetExtraLength());
2306 }
2307 return len;
2308 }
2309
SetNativePointerFieldCount(int32_t count)2310 void ECMAObject::SetNativePointerFieldCount(int32_t count)
2311 {
2312 if (count == 0) {
2313 return;
2314 }
2315 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2316 JSThread *thread = this->GetJSThread();
2317 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(hashField));
2318 JSHandle<ECMAObject> obj(thread, this);
2319 if (value->IsHeapObject()) {
2320 if (value->IsTaggedArray()) {
2321 JSHandle<TaggedArray> array(value);
2322 // Native Pointer field count is fixed.
2323 if (array->GetExtraLength() == 0) {
2324 JSHandle<TaggedArray> newArray =
2325 thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + RESOLVED_MAX_SIZE);
2326 newArray->SetExtraLength(count);
2327 newArray->Set(thread, count + HASH_INDEX, array->Get(HASH_INDEX));
2328 newArray->Set(thread, count + FUNCTION_EXTRA_INDEX, array->Get(FUNCTION_EXTRA_INDEX));
2329 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2330 }
2331 } else if (value->IsJSNativePointer()) {
2332 JSHandle<TaggedArray> newArray =
2333 thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + RESOLVED_MAX_SIZE);
2334 newArray->SetExtraLength(count);
2335 newArray->Set(thread, count + HASH_INDEX, JSTaggedValue(0));
2336 newArray->Set(thread, count + FUNCTION_EXTRA_INDEX, value);
2337 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2338 } else {
2339 LOG_ECMA(FATAL) << "this branch is unreachable";
2340 UNREACHABLE();
2341 }
2342 } else {
2343 JSHandle<TaggedArray> newArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + 1);
2344 newArray->SetExtraLength(count);
2345 newArray->Set(thread, count + HASH_INDEX, value);
2346 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2347 }
2348 }
2349 } // namespace panda::ecmascript
2350