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 isInternalAccessor = false;
749 if (op->IsAccessorDescriptor()) {
750 JSTaggedValue ret = ShouldGetValueFromBox(op);
751 isInternalAccessor = AccessorData::Cast(ret.GetTaggedObject())->IsInternal();
752 }
753 hasReceiver = true;
754 }
755 bool isSuccess = true;
756 if (op->IsFound() && !op->IsOnPrototype()) {
757 // i. If IsAccessorDescriptor(existingDescriptor) is true, return false.
758 if (op->IsAccessorDescriptor() && !isInternalAccessor) {
759 return false;
760 }
761
762 // ii. If existingDescriptor.[[Writable]] is false, return false.
763 if (!op->IsWritable()) {
764 if (mayThrow) {
765 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot assign to read only property", false);
766 }
767 return false;
768 }
769 isSuccess = op->UpdateDataValue(JSHandle<JSObject>(receiver), value, isInternalAccessor, mayThrow);
770 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, isSuccess);
771 } else {
772 // 5f. Else if Receiver does not currently have a property P, Return CreateDataProperty(Receiver, P, V).
773 if (!receiver->IsExtensible(thread)) {
774 if (mayThrow) {
775 THROW_TYPE_ERROR_AND_RETURN(thread, "receiver is not Extensible", false);
776 }
777 return false;
778 }
779 if (hasReceiver || isInternalAccessor) {
780 return op->AddProperty(JSHandle<JSObject>(receiver), value, PropertyAttributes::Default());
781 } else {
782 return op->AddProperty(JSHandle<JSObject>(receiver), value, op->GetAttr());
783 }
784 }
785 return isSuccess;
786 }
787 // 6. Assert: IsAccessorDescriptor(ownDesc) is true.
788 ASSERT(op->IsAccessorDescriptor());
789 // 8. If setter is undefined, return false.
790 JSTaggedValue ret = ShouldGetValueFromBox(op);
791 AccessorData *accessor = AccessorData::Cast(ret.GetTaggedObject());
792 return CallSetter(thread, *accessor, receiver, value, mayThrow);
793 }
794
CallSetter(JSThread * thread,const AccessorData & accessor,const JSHandle<JSTaggedValue> & receiver,const JSHandle<JSTaggedValue> & value,bool mayThrow)795 bool JSObject::CallSetter(JSThread *thread, const AccessorData &accessor, const JSHandle<JSTaggedValue> &receiver,
796 const JSHandle<JSTaggedValue> &value, bool mayThrow)
797 {
798 if (UNLIKELY(accessor.IsInternal())) {
799 return accessor.CallInternalSet(thread, JSHandle<JSObject>::Cast(receiver), value, mayThrow);
800 }
801 JSTaggedValue setter = accessor.GetSetter();
802 // 8. If setter is undefined, return false.
803 if (setter.IsUndefined()) {
804 if (mayThrow) {
805 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property when setter is undefined", false);
806 }
807 return false;
808 }
809
810 JSHandle<JSTaggedValue> func(thread, setter);
811 if (thread->IsPGOProfilerEnable()) {
812 auto profiler = thread->GetEcmaVM()->GetPGOProfiler();
813 profiler->ProfileCall(JSTaggedValue::VALUE_UNDEFINED, func.GetTaggedType());
814 }
815 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
816 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, receiver, undefined, 1);
817 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
818 info->SetCallArg(value.GetTaggedValue());
819 JSFunction::Call(info);
820
821 // 10. ReturnIfAbrupt(setterResult).
822 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
823
824 return true;
825 }
826
CallGetter(JSThread * thread,const AccessorData * accessor,const JSHandle<JSTaggedValue> & receiver)827 JSTaggedValue JSObject::CallGetter(JSThread *thread, const AccessorData *accessor,
828 const JSHandle<JSTaggedValue> &receiver)
829 {
830 JSTaggedValue getter = accessor->GetGetter();
831 // 7. If getter is undefined, return undefined.
832 if (getter.IsUndefined()) {
833 return JSTaggedValue::Undefined();
834 }
835
836 JSHandle<JSTaggedValue> func(thread, getter);
837 if (thread->IsPGOProfilerEnable()) {
838 auto profiler = thread->GetEcmaVM()->GetPGOProfiler();
839 profiler->ProfileCall(JSTaggedValue::VALUE_UNDEFINED, func.GetTaggedType());
840 }
841 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
842 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, receiver, undefined, 0);
843 JSTaggedValue res = JSFunction::Call(info);
844 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
845 return res;
846 }
847
848 // 9.1.8 [[Get]] (P, Receiver)
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)849 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
850 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
851 {
852 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
853 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
854
855 ObjectOperator op(thread, obj, receiver, key);
856 return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
857 }
858
GetProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key)859 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSObject> &obj,
860 const JSHandle<JSTaggedValue> &key)
861 {
862 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid JSObject");
863 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
864
865 ObjectOperator op(thread, obj, key);
866 return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
867 }
868
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)869 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
870 const JSHandle<JSTaggedValue> &key)
871 {
872 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
873 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
874
875 ObjectOperator op(thread, obj, key);
876 return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
877 }
878
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t index)879 OperationResult JSObject::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index)
880 {
881 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
882
883 ObjectOperator op(thread, obj, index);
884 return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
885 }
886
GetPropertyFromGlobal(JSThread * thread,const JSHandle<JSTaggedValue> & key)887 OperationResult JSObject::GetPropertyFromGlobal(JSThread *thread, const JSHandle<JSTaggedValue> &key)
888 {
889 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
890
891 ObjectOperator op(thread, key);
892 return OperationResult(thread, GetProperty(thread, &op), PropertyMetaData(op.IsFound()));
893 }
894
GetProperty(JSThread * thread,ObjectOperator * op)895 JSTaggedValue JSObject::GetProperty(JSThread *thread, ObjectOperator *op)
896 {
897 JSHandle<JSTaggedValue> receiver = op->GetReceiver();
898 JSHandle<JSTaggedValue> holder = op->GetHolder();
899 if (holder->IsJSProxy()) {
900 if (op->IsElement()) {
901 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(op->GetElementIndex()));
902 return JSProxy::GetProperty(thread, JSHandle<JSProxy>::Cast(holder), key, receiver)
903 .GetValue()
904 .GetTaggedValue();
905 }
906 return JSProxy::GetProperty(thread, JSHandle<JSProxy>::Cast(holder), op->GetKey(), receiver)
907 .GetValue()
908 .GetTaggedValue();
909 }
910
911 // 4. If desc is undefined, then
912 if (!op->IsFound()) {
913 // 4c. If obj and parent is null, return undefined.
914 return JSTaggedValue::Undefined();
915 }
916 // 5. If IsDataDescriptor(desc) is true, return desc.[[Value]]
917 JSTaggedValue ret = ShouldGetValueFromBox(op);
918 if (!op->IsAccessorDescriptor()) {
919 return ret;
920 }
921
922 // 6. Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].
923 AccessorData *accessor = AccessorData::Cast(ret.GetTaggedObject());
924 // 8. Return Call(getter, Receiver).
925 if (UNLIKELY(accessor->IsInternal())) {
926 return accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(holder));
927 }
928 return CallGetter(thread, accessor, receiver);
929 }
930
DeleteProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key)931 bool JSObject::DeleteProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key)
932 {
933 // 1. Assert: IsPropertyKey(P) is true.
934 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
935 // 2. Let desc be O.[[GetOwnProperty]](P).
936
937 ObjectOperator op(thread, JSHandle<JSTaggedValue>(obj), key, OperatorType::OWN);
938
939 // 4. If desc is undefined, return true.
940 if (!op.IsFound()) {
941 return true;
942 }
943 // 5. If desc.[[Configurable]] is true, then
944 // a. Remove the own property with name P from O.
945 // b. Return true.
946 // 6. Return false.
947 if (op.IsConfigurable()) {
948 op.DeletePropertyInHolder();
949 obj->GetClass()->SetHasDeleteProperty(true);
950 return true;
951 }
952 return false;
953 }
954
GetOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)955 bool JSObject::GetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
956 PropertyDescriptor &desc)
957 {
958 return OrdinaryGetOwnProperty(thread, obj, key, desc);
959 }
960
GlobalGetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)961 bool JSObject::GlobalGetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
962 {
963 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
964 ObjectOperator op(thread, key, OperatorType::OWN);
965
966 if (!op.IsFound()) {
967 return false;
968 }
969
970 op.ToPropertyDescriptor(desc);
971
972 if (desc.HasValue()) {
973 PropertyBox *cell = PropertyBox::Cast(desc.GetValue().GetTaggedValue().GetTaggedObject());
974 JSHandle<JSTaggedValue> valueHandle(thread, cell->GetValue());
975 desc.SetValue(valueHandle);
976 }
977 ASSERT(!desc.GetValue()->IsInternalAccessor());
978 return true;
979 }
980
OrdinaryGetOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)981 bool JSObject::OrdinaryGetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
982 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
983 {
984 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
985 ObjectOperator op(thread, JSHandle<JSTaggedValue>(obj), key, OperatorType::OWN);
986
987 if (!op.IsFound()) {
988 return false;
989 }
990
991 op.ToPropertyDescriptor(desc);
992
993 if (desc.HasValue() && obj->IsJSGlobalObject()) {
994 JSTaggedValue val = desc.GetValue().GetTaggedValue();
995 if (val.IsPropertyBox()) {
996 PropertyBox *cell = PropertyBox::Cast(val.GetTaggedObject());
997 JSHandle<JSTaggedValue> valueHandle(thread, cell->GetValue());
998 desc.SetValue(valueHandle);
999 }
1000 }
1001
1002 return true;
1003 }
1004
DefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)1005 bool JSObject::DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1006 const PropertyDescriptor &desc)
1007 {
1008 return OrdinaryDefineOwnProperty(thread, obj, key, desc);
1009 }
1010
DefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const PropertyDescriptor & desc)1011 bool JSObject::DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1012 const PropertyDescriptor &desc)
1013 {
1014 return OrdinaryDefineOwnProperty(thread, obj, index, desc);
1015 }
1016
1017 // 9.1.6.1 OrdinaryDefineOwnProperty (O, P, Desc)
OrdinaryDefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)1018 bool JSObject::OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj,
1019 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
1020 {
1021 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1022 // 1. Let current be O.[[GetOwnProperty]](P).
1023 JSHandle<JSTaggedValue> objValue(obj);
1024 ObjectOperator op(thread, objValue, key, OperatorType::OWN);
1025
1026 bool extensible = obj->IsExtensible();
1027 PropertyDescriptor current(thread);
1028 op.ToPropertyDescriptor(current);
1029 // 4. Return ValidateAndApplyPropertyDescriptor(O, P, extensible, Desc, current).
1030 return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current);
1031 }
1032
OrdinaryDefineOwnProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const PropertyDescriptor & desc)1033 bool JSObject::OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1034 const PropertyDescriptor &desc)
1035 {
1036 JSHandle<JSTaggedValue> objValue(obj);
1037 ObjectOperator op(thread, objValue, index, OperatorType::OWN);
1038
1039 bool extensible = obj->IsExtensible();
1040 PropertyDescriptor current(thread);
1041 op.ToPropertyDescriptor(current);
1042 return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current);
1043 }
1044
1045 // 9.1.6.3 ValidateAndApplyPropertyDescriptor (O, P, extensible, Desc, current)
ValidateAndApplyPropertyDescriptor(ObjectOperator * op,bool extensible,const PropertyDescriptor & desc,const PropertyDescriptor & current)1046 bool JSObject::ValidateAndApplyPropertyDescriptor(ObjectOperator *op, bool extensible, const PropertyDescriptor &desc,
1047 const PropertyDescriptor ¤t)
1048 {
1049 // 2. If current is undefined, then
1050 if (current.IsEmpty()) {
1051 // 2a. If extensible is false, return false.
1052 if (!extensible) {
1053 return false;
1054 }
1055 if (!op->HasHolder()) {
1056 return true;
1057 }
1058
1059 // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then
1060 PropertyAttributes attr(desc);
1061 bool success = false;
1062 if (!desc.IsAccessorDescriptor()) {
1063 success = op->AddPropertyInHolder(desc.GetValue(), attr);
1064 } else { // is AccessorDescriptor
1065 // may GC in NewAccessorData, so we need to handle getter and setter.
1066 JSThread *thread = op->GetThread();
1067 JSHandle<AccessorData> accessor = thread->GetEcmaVM()->GetFactory()->NewAccessorData();
1068 if (desc.HasGetter()) {
1069 accessor->SetGetter(thread, desc.GetGetter());
1070 }
1071
1072 if (desc.HasSetter()) {
1073 accessor->SetSetter(thread, desc.GetSetter());
1074 }
1075 success = op->AddPropertyInHolder(JSHandle<JSTaggedValue>::Cast(accessor), attr);
1076 }
1077
1078 return success;
1079 }
1080
1081 // 3. Return true, if every field in Desc is absent
1082 // 4. Return true, if every field in Desc also occurs in current and the value of every field in Desc is the
1083 // same value as the corresponding field in current when compared using the SameValue algorithm.
1084 if ((!desc.HasEnumerable() || desc.IsEnumerable() == current.IsEnumerable()) &&
1085 (!desc.HasConfigurable() || desc.IsConfigurable() == current.IsConfigurable()) &&
1086 (!desc.HasValue() || JSTaggedValue::SameValue(current.GetValue(), desc.GetValue())) &&
1087 (!desc.HasWritable() || (current.IsWritable() == desc.IsWritable())) &&
1088 (!desc.HasGetter() ||
1089 (current.HasGetter() && JSTaggedValue::SameValue(current.GetGetter(), desc.GetGetter()))) &&
1090 (!desc.HasSetter() ||
1091 (current.HasSetter() && JSTaggedValue::SameValue(current.GetSetter(), desc.GetSetter())))) {
1092 return true;
1093 }
1094
1095 // 5. If the [[Configurable]] field of current is false, then
1096 if (!current.IsConfigurable()) {
1097 // 5a. Return false, if the [[Configurable]] field of Desc is true.
1098 if (desc.HasConfigurable() && desc.IsConfigurable()) {
1099 return false;
1100 }
1101 // b. Return false, if the [[Enumerable]] field of Desc is present and the [[Enumerable]] fields of current
1102 // and Desc are the Boolean negation of each other.
1103 if (desc.HasEnumerable() && (desc.IsEnumerable() != current.IsEnumerable())) {
1104 return false;
1105 }
1106 }
1107
1108 // 6. If IsGenericDescriptor(Desc) is true, no further validation is required.
1109 if (desc.IsGenericDescriptor()) {
1110 // 7. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) have different results, then
1111 } else if (current.IsDataDescriptor() != desc.IsDataDescriptor()) {
1112 // 7a. Return false, if the [[Configurable]] field of current is false.
1113 if (!current.IsConfigurable()) {
1114 return false;
1115 }
1116 // 7b. If IsDataDescriptor(current) is true, then
1117 if (current.IsDataDescriptor()) {
1118 // 7bi. If O is not undefined, convert the property named P of object O from a data property to an
1119 // accessor property. Preserve the existing values of the converted property’s [[Configurable]] and
1120 // [[Enumerable]] attributes and set the rest of the property’s attributes to their default values.
1121 } else {
1122 // 7ci. If O is not undefined, convert the property named P of object O from an accessor property to a
1123 // data property. Preserve the existing values of the converted property’s [[Configurable]] and
1124 // [[Enumerable]] attributes and set the rest of the property’s attributes to their default values.
1125 }
1126 // 8. Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
1127 } else if (current.IsDataDescriptor() && desc.IsDataDescriptor()) {
1128 // 8a. If the [[Configurable]] field of current is false, then
1129 if (!current.IsConfigurable()) {
1130 // 8a i. Return false, if the [[Writable]] field of current is false and the [[Writable]] field of Desc
1131 // is true.
1132 if (!current.IsWritable() && desc.HasWritable() && desc.IsWritable()) {
1133 return false;
1134 }
1135 // 8a ii. If the [[Writable]] field of current is false, then
1136 if (!current.IsWritable()) {
1137 if (desc.HasValue() && !JSTaggedValue::SameValue(current.GetValue(), desc.GetValue())) {
1138 return false;
1139 }
1140 }
1141 }
1142 // 8b. Else the [[Configurable]] field of current is true, so any change is acceptable.
1143 } else { // 9. Else IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true,
1144 // 9a. If the [[Configurable]] field of current is false, then
1145 if (!current.IsConfigurable()) {
1146 // i. Return false, if the [[Set]] field of Desc is present and SameValue(Desc.[[Set]], current.[[Set]])
1147 // is false.
1148 if (desc.HasSetter() && !JSTaggedValue::SameValue(current.GetSetter(), desc.GetSetter())) {
1149 return false;
1150 }
1151 // ii. Return false, if the [[Get]] field of Desc is present and SameValue(Desc.[[Get]],
1152 // current.[[Get]]) is false.
1153 if (desc.HasGetter() && !JSTaggedValue::SameValue(current.GetGetter(), desc.GetGetter())) {
1154 return false;
1155 }
1156 }
1157 }
1158
1159 if (op->HasHolder()) {
1160 // 10. If O is not undefined, then
1161 // a. For each field of Desc that is present, set the corresponding attribute of the property named P of object
1162 // O to the value of the field.
1163 return op->WriteDataPropertyInHolder(desc);
1164 }
1165 return true;
1166 }
1167
1168 // 9.1.6.2 IsCompatiblePropertyDescriptor (Extensible, Desc, Current)
IsCompatiblePropertyDescriptor(bool extensible,const PropertyDescriptor & desc,const PropertyDescriptor & current)1169 bool JSObject::IsCompatiblePropertyDescriptor(bool extensible, const PropertyDescriptor &desc,
1170 const PropertyDescriptor ¤t)
1171 {
1172 // 1. Return ValidateAndApplyPropertyDescriptor(undefined, undefined, Extensible, Desc, Current).
1173 ObjectOperator op;
1174 return ValidateAndApplyPropertyDescriptor(&op, extensible, desc, current);
1175 }
1176
GetPrototype(const JSHandle<JSObject> & obj)1177 JSTaggedValue JSObject::GetPrototype(const JSHandle<JSObject> &obj)
1178 {
1179 JSHClass *hclass = obj->GetJSHClass();
1180 return hclass->GetPrototype();
1181 }
1182
SetPrototype(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & proto)1183 bool JSObject::SetPrototype(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &proto)
1184 {
1185 ASSERT_PRINT(proto->IsECMAObject() || proto->IsNull(), "proto must be object or null");
1186 JSTaggedValue current = JSObject::GetPrototype(obj);
1187 if (current == proto.GetTaggedValue()) {
1188 return true;
1189 }
1190 if (!obj->IsExtensible()) {
1191 return false;
1192 }
1193 bool done = false;
1194 JSMutableHandle<JSTaggedValue> tempProtoHandle(thread, proto.GetTaggedValue());
1195 while (!done) {
1196 if (tempProtoHandle->IsNull() || !tempProtoHandle->IsECMAObject()) {
1197 done = true;
1198 } else if (JSTaggedValue::SameValue(tempProtoHandle.GetTaggedValue(), obj.GetTaggedValue())) {
1199 return false;
1200 } else {
1201 if (tempProtoHandle->IsJSProxy()) {
1202 break;
1203 }
1204 tempProtoHandle.Update(JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(tempProtoHandle)));
1205 }
1206 }
1207 // map transition
1208 JSHandle<JSHClass> hclass(thread, obj->GetJSHClass());
1209 JSHandle<JSHClass> newClass = JSHClass::TransitionProto(thread, hclass, proto);
1210 JSHClass::NotifyHclassChanged(thread, hclass, newClass);
1211 obj->SynchronizedSetClass(*newClass);
1212 thread->NotifyStableArrayElementsGuardians(obj, StableArrayChangeKind::PROTO);
1213 return true;
1214 }
1215
GetCtorFromPrototype(JSThread * thread,JSTaggedValue prototype)1216 JSTaggedValue JSObject::GetCtorFromPrototype(JSThread *thread, JSTaggedValue prototype)
1217 {
1218 if (!prototype.IsJSObject()) {
1219 return JSTaggedValue::Undefined();
1220 }
1221 JSHandle<JSTaggedValue> object(thread, prototype);
1222 JSHandle<JSTaggedValue> ctorKey = thread->GlobalConstants()->GetHandledConstructorString();
1223 JSHandle<JSTaggedValue> ctorObj(JSObject::GetProperty(thread, object, ctorKey).GetValue());
1224 if (thread->HasPendingException()) {
1225 thread->ClearException();
1226 return JSTaggedValue::Undefined();
1227 }
1228 return ctorObj.GetTaggedValue();
1229 }
1230
HasProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key)1231 bool JSObject::HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key)
1232 {
1233 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1234 JSHandle<JSTaggedValue> objValue(obj);
1235 ObjectOperator op(thread, objValue, key);
1236
1237 JSHandle<JSTaggedValue> holder = op.GetHolder();
1238 if (holder->IsJSProxy()) {
1239 return JSProxy::HasProperty(thread, JSHandle<JSProxy>::Cast(holder), key);
1240 }
1241
1242 return op.IsFound();
1243 }
1244
HasProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index)1245 bool JSObject::HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index)
1246 {
1247 JSHandle<JSTaggedValue> objValue(obj);
1248 ObjectOperator op(thread, objValue, index);
1249
1250 JSHandle<JSTaggedValue> holder = op.GetHolder();
1251 if (holder->IsJSProxy()) {
1252 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(index));
1253 return JSProxy::HasProperty(thread, JSHandle<JSProxy>::Cast(holder), key);
1254 }
1255
1256 return op.IsFound();
1257 }
1258
PreventExtensions(JSThread * thread,const JSHandle<JSObject> & obj)1259 bool JSObject::PreventExtensions(JSThread *thread, const JSHandle<JSObject> &obj)
1260 {
1261 if (obj->IsExtensible()) {
1262 JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
1263 JSHandle<JSHClass> newHclass = JSHClass::TransitionExtension(thread, jshclass);
1264 obj->SynchronizedSetClass(*newHclass);
1265 }
1266
1267 return true;
1268 }
1269
1270 // 9.1.12 [[OwnPropertyKeys]] ( )
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSObject> & obj)1271 JSHandle<TaggedArray> JSObject::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj)
1272 {
1273 uint32_t numOfElements = obj->GetNumberOfElements();
1274 uint32_t keyLen = numOfElements + obj->GetNumberOfKeys();
1275
1276 JSHandle<TaggedArray> keyArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(keyLen);
1277
1278 if (numOfElements > 0) {
1279 GetAllElementKeys(thread, obj, 0, keyArray);
1280 }
1281 GetAllKeys(thread, obj, static_cast<int32_t>(numOfElements), keyArray);
1282 return keyArray;
1283 }
1284
GetAllPropertyKeys(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t filter)1285 JSHandle<TaggedArray> JSObject::GetAllPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t filter)
1286 {
1287 JSMutableHandle<JSObject> currentObj(thread, obj);
1288 JSMutableHandle<JSTaggedValue> currentObjValue(thread, currentObj);
1289
1290 uint32_t curObjNumberOfElements = currentObj->GetNumberOfElements();
1291 uint32_t curObjNumberOfKeys = currentObj->GetNumberOfKeys();
1292 uint32_t curObjectKeysLength = curObjNumberOfElements + curObjNumberOfKeys;
1293 uint32_t retArrayLength = curObjectKeysLength;
1294 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1295 JSMutableHandle<TaggedArray> retArray(thread, factory->NewTaggedArray(retArrayLength));
1296 uint32_t retArrayEffectivelength = 0;
1297
1298 do {
1299 curObjNumberOfElements = currentObj->GetNumberOfElements();
1300 curObjNumberOfKeys = currentObj->GetNumberOfKeys();
1301 curObjectKeysLength = curObjNumberOfElements + curObjNumberOfKeys;
1302 uint32_t minRequireLength = curObjectKeysLength + retArrayEffectivelength;
1303 if (retArrayLength < minRequireLength) {
1304 // expand retArray
1305 retArray.Update(factory->NewAndCopyTaggedArray(retArray, minRequireLength, retArrayLength));
1306 retArrayLength = minRequireLength;
1307 }
1308
1309 GetAllElementKeysByFilter(thread, currentObj, retArray, retArrayEffectivelength, filter);
1310
1311 GetAllKeysByFilter(thread, currentObj, retArrayEffectivelength, retArray, filter);
1312 bool isInculdePrototypes = (filter & NATIVE_KEY_INCLUDE_PROTOTYPES);
1313 if (!isInculdePrototypes) {
1314 break;
1315 }
1316 currentObj.Update(GetPrototype(currentObj));
1317 currentObjValue.Update(currentObj);
1318 } while (currentObjValue->IsHeapObject());
1319
1320 JSMutableHandle<JSTaggedValue> element(thread, JSTaggedValue::Undefined());
1321 if (filter & NATIVE_KEY_NUMBERS_TO_STRINGS) {
1322 for (uint32_t i = 0; i < retArrayEffectivelength; i++) {
1323 element.Update(retArray->Get(i));
1324 if (element->IsNumber()) {
1325 retArray->Set(thread, i, base::NumberHelper::NumberToString(thread,
1326 JSTaggedValue(element->GetNumber())));
1327 }
1328 }
1329 }
1330 uint32_t elementIndex = 0;
1331 while ((filter & NATIVE_KEY_SKIP_STRINGS) && (retArrayEffectivelength > 0) &&
1332 (elementIndex < retArrayEffectivelength)) {
1333 if (retArray->Get(elementIndex).IsString()) {
1334 TaggedArray::RemoveElementByIndex(thread, retArray, elementIndex, retArrayEffectivelength);
1335 retArrayEffectivelength--;
1336 } else {
1337 elementIndex++;
1338 }
1339 }
1340 retArray->Trim(thread, retArrayEffectivelength);
1341 return retArray;
1342 }
1343
GetOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSObject> & obj)1344 JSHandle<TaggedArray> JSObject::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj)
1345 {
1346 uint32_t numOfElements = obj->GetNumberOfElements();
1347 uint32_t keyLen = numOfElements + obj->GetNumberOfKeys();
1348
1349 JSHandle<TaggedArray> keyArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(keyLen);
1350
1351 if (numOfElements > 0) {
1352 GetEnumElementKeys(thread, obj, 0, keyArray);
1353 }
1354 GetAllEnumKeys(thread, obj, static_cast<int32_t>(numOfElements), keyArray);
1355 return keyArray;
1356 }
1357
ObjectCreate(JSThread * thread,const JSHandle<JSObject> & proto)1358 JSHandle<JSObject> JSObject::ObjectCreate(JSThread *thread, const JSHandle<JSObject> &proto)
1359 {
1360 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1361 JSHandle<JSFunction> constructor(env->GetObjectFunction());
1362 JSHandle<JSObject> objHandle = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(constructor);
1363 SetPrototype(thread, objHandle, JSHandle<JSTaggedValue>(proto));
1364 return objHandle;
1365 }
1366
1367 // 7.3.4 CreateDataProperty (O, P, V)
CreateDataProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1368 bool JSObject::CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1369 const JSHandle<JSTaggedValue> &value)
1370 {
1371 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1372 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1373 auto result = ObjectFastOperator::SetPropertyByValue<true>(thread, obj.GetTaggedValue(), key.GetTaggedValue(),
1374 value.GetTaggedValue());
1375 if (!result.IsHole()) {
1376 return !result.IsException();
1377 }
1378 PropertyDescriptor desc(thread, value, true, true, true);
1379 return JSTaggedValue::DefineOwnProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key, desc);
1380 }
1381
CreateDataProperty(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const JSHandle<JSTaggedValue> & value)1382 bool JSObject::CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1383 const JSHandle<JSTaggedValue> &value)
1384 {
1385 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1386 auto result =
1387 ObjectFastOperator::SetPropertyByIndex<true>(thread, obj.GetTaggedValue(), index, value.GetTaggedValue());
1388 if (!result.IsHole()) {
1389 return !result.IsException();
1390 }
1391 PropertyDescriptor desc(thread, value, true, true, true);
1392 return DefineOwnProperty(thread, obj, index, desc);
1393 }
1394
1395 // 7.3.5 CreateMethodProperty (O, P, V)
CreateDataPropertyOrThrow(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1396 bool JSObject::CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj,
1397 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value)
1398 {
1399 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1400 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1401
1402 bool success = CreateDataProperty(thread, obj, key, value);
1403 if (!success) {
1404 THROW_TYPE_ERROR_AND_RETURN(thread, "failed to create data property", success);
1405 }
1406 return success;
1407 }
1408
CreateDataPropertyOrThrow(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t index,const JSHandle<JSTaggedValue> & value)1409 bool JSObject::CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index,
1410 const JSHandle<JSTaggedValue> &value)
1411 {
1412 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1413
1414 bool success = CreateDataProperty(thread, obj, index, value);
1415 if (!success) {
1416 THROW_TYPE_ERROR_AND_RETURN(thread, "failed to create data property", success);
1417 }
1418 return success;
1419 }
1420 // 7.3.6 CreateDataPropertyOrThrow (O, P, V)
CreateMethodProperty(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1421 bool JSObject::CreateMethodProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
1422 const JSHandle<JSTaggedValue> &value)
1423 {
1424 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1425 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1426
1427 PropertyDescriptor desc(thread, value, true, false, true);
1428 return DefineOwnProperty(thread, obj, key, desc);
1429 }
1430
1431 // 7.3.9 GetMethod (O, P)
GetMethod(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1432 JSHandle<JSTaggedValue> JSObject::GetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1433 const JSHandle<JSTaggedValue> &key)
1434 {
1435 JSHandle<JSTaggedValue> func = JSTaggedValue::GetProperty(thread, obj, key).GetValue();
1436 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1437 if (func->IsUndefined() || func->IsNull()) {
1438 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
1439 }
1440
1441 if (!func->IsCallable()) {
1442 THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not Callable", func);
1443 }
1444 return func;
1445 }
1446
1447 // 7.3.14 SetIntegrityLevel (O, level)
SetIntegrityLevel(JSThread * thread,const JSHandle<JSObject> & obj,IntegrityLevel level)1448 bool JSObject::SetIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level)
1449 {
1450 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1451 ASSERT_PRINT((level == IntegrityLevel::SEALED || level == IntegrityLevel::FROZEN),
1452 "level is not a valid IntegrityLevel");
1453
1454 bool status = JSTaggedValue::PreventExtensions(thread, JSHandle<JSTaggedValue>(obj));
1455 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1456 if (!status) {
1457 return false;
1458 }
1459
1460 JSHandle<TaggedArray> jshandleKeys =
1461 JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>(obj));
1462 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1463 PropertyDescriptor descNoConf(thread);
1464 descNoConf.SetConfigurable(false);
1465 PropertyDescriptor descNoConfWrite(thread);
1466 descNoConfWrite.SetWritable(false);
1467 descNoConfWrite.SetConfigurable(false);
1468
1469 if (level == IntegrityLevel::SEALED) {
1470 uint32_t length = jshandleKeys->GetLength();
1471 if (length == 0) {
1472 return true;
1473 }
1474 auto key = jshandleKeys->Get(0);
1475 JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1476 for (uint32_t i = 0; i < length; i++) {
1477 auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1478 handleKey.Update(taggedKey);
1479 [[maybe_unused]] bool success =
1480 JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(obj), handleKey, descNoConf);
1481 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1482 }
1483 } else {
1484 uint32_t length = jshandleKeys->GetLength();
1485 if (length == 0) {
1486 return true;
1487 }
1488 auto key = jshandleKeys->Get(0);
1489 JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1490 for (uint32_t i = 0; i < length; i++) {
1491 auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1492 handleKey.Update(taggedKey);
1493 PropertyDescriptor currentDesc(thread);
1494 bool curDescStatus =
1495 JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), handleKey, currentDesc);
1496 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1497 if (curDescStatus) {
1498 PropertyDescriptor desc = currentDesc.IsAccessorDescriptor() ? descNoConf : descNoConfWrite;
1499 [[maybe_unused]] bool success =
1500 JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(obj), handleKey, desc);
1501 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1502 }
1503 }
1504 }
1505 return true;
1506 }
1507
1508 // 7.3.15 TestIntegrityLevel (O, level)
TestIntegrityLevel(JSThread * thread,const JSHandle<JSObject> & obj,IntegrityLevel level)1509 bool JSObject::TestIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level)
1510 {
1511 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1512 ASSERT_PRINT((level == IntegrityLevel::SEALED || level == IntegrityLevel::FROZEN),
1513 "level is not a valid IntegrityLevel");
1514
1515 bool status = JSHandle<JSTaggedValue>(obj)->IsExtensible(thread);
1516 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1517 if (status) {
1518 return false;
1519 }
1520
1521 JSHandle<TaggedArray> jshandleKeys =
1522 JSTaggedValue::GetOwnPropertyKeys(thread, JSHandle<JSTaggedValue>(obj));
1523 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1524 uint32_t length = jshandleKeys->GetLength();
1525 if (length == 0) {
1526 return true;
1527 }
1528 auto key = jshandleKeys->Get(0);
1529 JSMutableHandle<JSTaggedValue> handleKey(thread, key);
1530 for (uint32_t i = 0; i < length; i++) {
1531 auto taggedKey = JSTaggedValue(jshandleKeys->Get(i));
1532 handleKey.Update(taggedKey);
1533 PropertyDescriptor currentDesc(thread);
1534 bool curDescStatus =
1535 JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), handleKey, currentDesc);
1536 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1537 if (curDescStatus) {
1538 if (currentDesc.IsConfigurable()) {
1539 return false;
1540 }
1541 if (level == IntegrityLevel::FROZEN &&
1542 currentDesc.IsDataDescriptor() && currentDesc.IsWritable()) {
1543 return false;
1544 }
1545 }
1546 }
1547 return true;
1548 }
1549
1550 // 7.3.21 EnumerableOwnNames (O)
EnumerableOwnNames(JSThread * thread,const JSHandle<JSObject> & obj)1551 JSHandle<TaggedArray> JSObject::EnumerableOwnNames(JSThread *thread, const JSHandle<JSObject> &obj)
1552 {
1553 ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
1554 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1555 JSHandle<JSTaggedValue> tagObj(obj);
1556 // fast mode
1557 if (tagObj->IsJSObject() && !tagObj->IsTypedArray() && !tagObj->IsModuleNamespace()) {
1558 uint32_t copyLengthOfKeys = 0;
1559 uint32_t copyLengthOfElements = 0;
1560 auto keyElementPair = GetOwnEnumerableNamesInFastMode(thread, obj, ©LengthOfKeys, ©LengthOfElements);
1561 JSHandle<TaggedArray> keyArray = keyElementPair.first;
1562 JSHandle<TaggedArray> elementArray = keyElementPair.second;
1563 JSHandle<TaggedArray> keys;
1564 if (copyLengthOfKeys != 0 && copyLengthOfElements != 0) {
1565 keys = TaggedArray::AppendSkipHole(thread, elementArray, keyArray, copyLengthOfKeys + copyLengthOfElements);
1566 } else if (copyLengthOfKeys != 0) {
1567 keys = factory->CopyArray(keyArray, copyLengthOfKeys, copyLengthOfKeys);
1568 } else if (copyLengthOfElements != 0) {
1569 keys = factory->CopyArray(elementArray, copyLengthOfElements, copyLengthOfElements);
1570 } else {
1571 keys = factory->EmptyArray();
1572 }
1573 return keys;
1574 }
1575
1576 uint32_t copyLength = 0;
1577 JSHandle<TaggedArray> keys = JSTaggedValue::GetOwnPropertyKeys(thread, tagObj);
1578 RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1579 uint32_t length = keys->GetLength();
1580
1581 JSHandle<TaggedArray> names = factory->NewTaggedArray(length);
1582 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
1583 for (uint32_t i = 0; i < length; i++) {
1584 keyHandle.Update(keys->Get(i));
1585 if (keyHandle->IsString()) {
1586 PropertyDescriptor desc(thread);
1587 bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj),
1588 keyHandle, desc);
1589 RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1590
1591 if (status && desc.IsEnumerable()) {
1592 names->Set(thread, copyLength, keyHandle);
1593 copyLength++;
1594 }
1595 }
1596 }
1597
1598 return factory->CopyArray(names, length, copyLength);
1599 }
1600
EnumerableOwnPropertyNamesHelper(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<TaggedArray> & arr,JSHandle<TaggedArray> & prop,uint32_t & index,bool & fastMode,PropertyKind kind)1601 void JSObject::EnumerableOwnPropertyNamesHelper(JSThread *thread, const JSHandle<JSObject> &obj,
1602 const JSHandle<TaggedArray> &arr, JSHandle<TaggedArray> &prop, uint32_t &index, bool &fastMode, PropertyKind kind)
1603 {
1604 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1605 JSHandle<JSHClass> objClass(thread, obj->GetJSHClass());
1606 uint32_t length = arr->GetLength();
1607 for (uint32_t i = 0; i < length; i++) {
1608 key.Update(arr->Get(thread, i));
1609 if (!JSTaggedValue::IsPropertyKey(key)) {
1610 break;
1611 }
1612 JSTaggedValue value = JSTaggedValue::Hole();
1613 if (fastMode) {
1614 value = ObjectFastOperator::GetPropertyByValue<true>(thread, obj.GetTaggedValue(), key.GetTaggedValue());
1615 RETURN_IF_ABRUPT_COMPLETION(thread);
1616 }
1617 if (value.IsHole()) {
1618 PropertyDescriptor desc(thread);
1619 bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj), key, desc);
1620 RETURN_IF_ABRUPT_COMPLETION(thread);
1621 if (!status || !desc.IsEnumerable()) {
1622 continue;
1623 }
1624 if (desc.HasValue()) {
1625 value = desc.GetValue().GetTaggedValue();
1626 } else {
1627 OperationResult opResult = JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key);
1628 RETURN_IF_ABRUPT_COMPLETION(thread);
1629 value = opResult.GetValue().GetTaggedValue();
1630 }
1631 }
1632 index = SetValuesOrEntries(thread, prop, index, key, JSHandle<JSTaggedValue>(thread, value), kind);
1633 fastMode = fastMode ? CheckHClassHit(obj, objClass) : fastMode;
1634 }
1635 }
1636
EnumerableOwnPropertyNames(JSThread * thread,const JSHandle<JSObject> & obj,PropertyKind kind)1637 JSHandle<TaggedArray> JSObject::EnumerableOwnPropertyNames(JSThread *thread, const JSHandle<JSObject> &obj,
1638 PropertyKind kind)
1639 {
1640 // 1. Assert: Type(O) is Object.
1641 ASSERT_PRINT(obj->IsECMAObject(), "obj is not object");
1642
1643 // 2. Let ownKeys be ? O.[[OwnPropertyKeys]]().
1644 JSHandle<JSTaggedValue> tagObj(obj);
1645 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1646 if (tagObj->IsJSObject() && !tagObj->IsJSProxy() && !tagObj->IsTypedArray() && !tagObj->IsModuleNamespace()) {
1647 uint32_t copyLengthOfKeys = 0;
1648 uint32_t copyLengthOfElements = 0;
1649 uint32_t index = 0;
1650 bool fastMode = true;
1651 auto keyElementPair = GetOwnEnumerableNamesInFastMode(thread, obj, ©LengthOfKeys, ©LengthOfElements);
1652 JSHandle<TaggedArray> keyArray = keyElementPair.first;
1653 JSHandle<TaggedArray> elementArray = keyElementPair.second;
1654 JSHandle<TaggedArray> properties = factory->NewTaggedArray(copyLengthOfKeys + copyLengthOfElements);
1655 if (copyLengthOfElements != 0) {
1656 EnumerableOwnPropertyNamesHelper(thread, obj, elementArray, properties, index, fastMode, kind);
1657 }
1658 if (copyLengthOfKeys != 0) {
1659 EnumerableOwnPropertyNamesHelper(thread, obj, keyArray, properties, index, fastMode, kind);
1660 }
1661 if (UNLIKELY(!fastMode && index < copyLengthOfKeys + copyLengthOfElements)) {
1662 properties->Trim(thread, index);
1663 }
1664 return properties;
1665 }
1666
1667 JSHandle<TaggedArray> ownKeys = JSTaggedValue::GetOwnPropertyKeys(thread, tagObj);
1668 RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1669
1670 // 3. Let properties be a new empty List.
1671 uint32_t length = ownKeys->GetLength();
1672 JSHandle<TaggedArray> properties = factory->NewTaggedArray(length);
1673
1674 // 4. For each element key of ownKeys, do
1675 // a. If Type(key) is String, then
1676 // i. Let desc be ? O.[[GetOwnProperty]](key).
1677 // ii. If desc is not undefined and desc.[[Enumerable]] is true, then
1678 // 1. If kind is key, append key to properties.
1679 // 2. Else,
1680 // a. Let value be ? Get(O, key).
1681 // b. If kind is value, append value to properties.
1682 // c. Else,
1683 // i. Assert: kind is key+value.
1684 // ii. Let entry be ! CreateArrayFromList(« key, value »).
1685 // iii. Append entry to properties.
1686 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1687 uint32_t index = 0;
1688 for (uint32_t i = 0; i < length; i++) {
1689 key.Update(ownKeys->Get(thread, i));
1690 if (key->IsString()) {
1691 PropertyDescriptor desc(thread);
1692 bool status = JSTaggedValue::GetOwnProperty(thread, JSHandle<JSTaggedValue>(obj),
1693 key, desc);
1694 RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1695 if (status && desc.IsEnumerable()) {
1696 if (kind == PropertyKind::KEY) {
1697 properties->Set(thread, index++, key);
1698 } else {
1699 OperationResult result =
1700 JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), key);
1701 RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
1702 JSHandle<JSTaggedValue> value = result.GetValue();
1703 index = SetValuesOrEntries(thread, properties, index, key, value, kind);
1704 }
1705 }
1706 }
1707 }
1708
1709 if (UNLIKELY(index < length)) {
1710 properties->Trim(thread, index);
1711 }
1712 // 5. Return properties.
1713 return properties;
1714 }
1715
GetFunctionRealm(JSThread * thread,const JSHandle<JSTaggedValue> & object)1716 JSHandle<GlobalEnv> JSObject::GetFunctionRealm(JSThread *thread, const JSHandle<JSTaggedValue> &object)
1717 {
1718 // 1. Assert: obj is a callable object.
1719 ASSERT(object->IsCallable());
1720 // 2. If obj has a [[Realm]] internal slot, then return obj’s [[Realm]] internal slot.
1721 // 3. If obj is a Bound Function exotic object, then
1722 if (object->IsBoundFunction()) {
1723 // a. Let target be obj’s [[BoundTargetFunction]] internal slot.
1724 JSHandle<JSTaggedValue> target(thread, JSHandle<JSBoundFunction>(object)->GetBoundTarget());
1725 // b. Return GetFunctionRealm(target).
1726 return GetFunctionRealm(thread, target);
1727 }
1728 // 4. If obj is a Proxy exotic object, then
1729 if (object->IsJSProxy()) {
1730 // a. If the value of the [[ProxyHandler]] internal slot of obj is null, throw a TypeError exception.
1731 if (JSHandle<JSProxy>(object)->GetHandler().IsNull()) {
1732 THROW_TYPE_ERROR_AND_RETURN(thread, "JSObject::GetFunctionRealm: handler is null",
1733 JSHandle<GlobalEnv>(thread, JSTaggedValue::Exception()));
1734 }
1735 // b. Let proxyTarget be the value of obj’s [[ProxyTarget]] internal slot.
1736 JSHandle<JSTaggedValue> proxyTarget(thread, JSHandle<JSProxy>(object)->GetTarget());
1737 return GetFunctionRealm(thread, proxyTarget);
1738 }
1739 JSTaggedValue maybeGlobalEnv = JSHandle<JSFunction>(object)->GetLexicalEnv();
1740 while (!maybeGlobalEnv.IsJSGlobalEnv()) {
1741 if (maybeGlobalEnv.IsUndefined()) {
1742 return thread->GetEcmaVM()->GetGlobalEnv();
1743 }
1744 maybeGlobalEnv = LexicalEnv::Cast(maybeGlobalEnv.GetTaggedObject())->GetParentEnv();
1745 }
1746 return JSHandle<GlobalEnv>(thread, maybeGlobalEnv);
1747 }
1748
InstanceOf(JSThread * thread,const JSHandle<JSTaggedValue> & object,const JSHandle<JSTaggedValue> & target)1749 bool JSObject::InstanceOf(JSThread *thread, const JSHandle<JSTaggedValue> &object,
1750 const JSHandle<JSTaggedValue> &target)
1751 {
1752 // 1. If Type(target) is not Object, throw a TypeError exception.
1753 if (!target->IsECMAObject()) {
1754 THROW_TYPE_ERROR_AND_RETURN(thread, "InstanceOf error when type of target is not Object", false);
1755 }
1756
1757 EcmaVM *vm = thread->GetEcmaVM();
1758 // 2. Let instOfHandler be GetMethod(target, @@hasInstance).
1759 JSHandle<JSTaggedValue> instOfHandler = GetMethod(thread, target, vm->GetGlobalEnv()->GetHasInstanceSymbol());
1760
1761 // 3. ReturnIfAbrupt(instOfHandler).
1762 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1763
1764 // 4. If instOfHandler is not undefined, then
1765 if (!instOfHandler->IsUndefined()) {
1766 // a. Return ! ToBoolean(? Call(instOfHandler, target, «object»)).
1767 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1768 EcmaRuntimeCallInfo *info =
1769 EcmaInterpreter::NewRuntimeCallInfo(thread, instOfHandler, target, undefined, 1);
1770 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1771 info->SetCallArg(object.GetTaggedValue());
1772 JSTaggedValue tagged = JSFunction::Call(info);
1773 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1774 return tagged.ToBoolean();
1775 }
1776
1777 // 5. If IsCallable(target) is false, throw a TypeError exception.
1778 if (!target->IsCallable()) {
1779 THROW_TYPE_ERROR_AND_RETURN(thread, "InstanceOf error when target is not Callable", false);
1780 }
1781
1782 // 6. Return ? OrdinaryHasInstance(target, object).
1783 return JSFunction::OrdinaryHasInstance(thread, target, object);
1784 }
1785
1786 // ecma6.0 6.2.4.4
FromPropertyDescriptor(JSThread * thread,const PropertyDescriptor & desc)1787 JSHandle<JSTaggedValue> JSObject::FromPropertyDescriptor(JSThread *thread, const PropertyDescriptor &desc)
1788 {
1789 // 1. If Desc is undefined, return undefined
1790 if (desc.IsEmpty()) {
1791 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined());
1792 }
1793
1794 // 2. Let obj be ObjectCreate(%ObjectPrototype%).
1795 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1796 JSHandle<JSFunction> objFunc(env->GetObjectFunction());
1797 JSHandle<JSObject> objHandle = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(objFunc);
1798
1799 auto globalConst = thread->GlobalConstants();
1800 // 4. If Desc has a [[Value]] field, then Perform CreateDataProperty(obj, "value", Desc.[[Value]]).
1801 if (desc.HasValue()) {
1802 JSHandle<JSTaggedValue> valueStr = globalConst->GetHandledValueString();
1803 bool success = CreateDataProperty(thread, objHandle, valueStr, desc.GetValue());
1804 RASSERT_PRINT(success, "CreateDataProperty must be success");
1805 }
1806 // 5. If Desc has a [[Writable]] field, then Perform CreateDataProperty(obj, "writable", Desc.[[Writable]]).
1807 if (desc.HasWritable()) {
1808 JSHandle<JSTaggedValue> writableStr = globalConst->GetHandledWritableString();
1809 JSHandle<JSTaggedValue> writable(thread, JSTaggedValue(desc.IsWritable()));
1810 [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, writableStr, writable);
1811 ASSERT_PRINT(success, "CreateDataProperty must be success");
1812 }
1813 // 6. If Desc has a [[Get]] field, then Perform CreateDataProperty(obj, "get", Desc.[[Get]]).
1814 if (desc.HasGetter()) {
1815 JSHandle<JSTaggedValue> getStr = globalConst->GetHandledGetString();
1816 bool success = CreateDataProperty(thread, objHandle, getStr, desc.GetGetter());
1817 RASSERT_PRINT(success, "CreateDataProperty must be success");
1818 }
1819 // 7. If Desc has a [[Set]] field, then Perform CreateDataProperty(obj, "set", Desc.[[Set]])
1820 if (desc.HasSetter()) {
1821 JSHandle<JSTaggedValue> setStr = globalConst->GetHandledSetString();
1822 bool success = CreateDataProperty(thread, objHandle, setStr, desc.GetSetter());
1823 RASSERT_PRINT(success, "CreateDataProperty must be success");
1824 }
1825 // 8. If Desc has an [[Enumerable]] field, then Perform CreateDataProperty(obj, "enumerable",
1826 // Desc.[[Enumerable]]).
1827 if (desc.HasEnumerable()) {
1828 JSHandle<JSTaggedValue> enumerableStr = globalConst->GetHandledEnumerableString();
1829 JSHandle<JSTaggedValue> enumerable(thread, JSTaggedValue(desc.IsEnumerable()));
1830 [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, enumerableStr, enumerable);
1831 ASSERT_PRINT(success, "CreateDataProperty must be success");
1832 }
1833 // 9. If Desc has a [[Configurable]] field, then Perform CreateDataProperty(obj , "configurable",
1834 // Desc.[[Configurable]]).
1835 if (desc.HasConfigurable()) {
1836 JSHandle<JSTaggedValue> configurableStr = globalConst->GetHandledConfigurableString();
1837 JSHandle<JSTaggedValue> configurable(thread, JSTaggedValue(desc.IsConfigurable()));
1838 [[maybe_unused]] bool success = CreateDataProperty(thread, objHandle, configurableStr, configurable);
1839 ASSERT_PRINT(success, "CreateDataProperty must be success");
1840 }
1841 return JSHandle<JSTaggedValue>(objHandle);
1842 }
1843
ToPropertyDescriptorFast(JSThread * thread,const JSHandle<JSTaggedValue> & obj,PropertyDescriptor & desc)1844 bool JSObject::ToPropertyDescriptorFast(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc)
1845 {
1846 auto *hclass = obj->GetTaggedObject()->GetClass();
1847 JSType jsType = hclass->GetObjectType();
1848 if (jsType != JSType::JS_OBJECT) {
1849 return false;
1850 }
1851 if (hclass->IsDictionaryMode()) {
1852 return false;
1853 }
1854 auto env = thread->GetEcmaVM()->GetGlobalEnv();
1855 auto globalConst = thread->GlobalConstants();
1856 if (hclass->GetPrototype() != env->GetObjectFunctionPrototype().GetTaggedValue()) {
1857 return false;
1858 }
1859 if (JSObject::Cast(hclass->GetPrototype().GetTaggedObject())->GetClass() !=
1860 env->GetObjectFunctionPrototypeClass().GetObject<JSHClass>()) {
1861 return false;
1862 }
1863 LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
1864 uint32_t propsNumber = hclass->NumberOfProps();
1865 for (uint32_t i = 0; i < propsNumber; i++) {
1866 auto attr = layoutInfo->GetAttr(i);
1867 if (attr.IsAccessor()) {
1868 return false;
1869 }
1870 auto key = layoutInfo->GetKey(i);
1871 auto value = JSObject::Cast(obj->GetTaggedObject())->GetProperty(hclass, attr);
1872 if (key == globalConst->GetEnumerableString()) {
1873 bool enumerable = value.ToBoolean();
1874 desc.SetEnumerable(enumerable);
1875 } else if (key == globalConst->GetConfigurableString()) {
1876 bool configurable = value.ToBoolean();
1877 desc.SetConfigurable(configurable);
1878 } else if (key == globalConst->GetValueString()) {
1879 auto handleValue = JSHandle<JSTaggedValue>(thread, value);
1880 desc.SetValue(handleValue);
1881 } else if (key == globalConst->GetWritableString()) {
1882 bool writable = value.ToBoolean();
1883 desc.SetWritable(writable);
1884 } else if (key == globalConst->GetGetString()) {
1885 if (!value.IsCallable()) {
1886 return false;
1887 }
1888 auto getter = JSHandle<JSTaggedValue>(thread, value);
1889 desc.SetGetter(getter);
1890 } else if (key == globalConst->GetSetString()) {
1891 if (!value.IsCallable()) {
1892 return false;
1893 }
1894 auto setter = JSHandle<JSTaggedValue>(thread, value);
1895 desc.SetSetter(setter);
1896 }
1897 }
1898
1899 if (desc.IsAccessorDescriptor()) {
1900 // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, throw a TypeError exception.
1901 if (desc.HasValue() || desc.HasWritable()) {
1902 THROW_TYPE_ERROR_AND_RETURN(thread, "either Value or Writable is present", true);
1903 }
1904 }
1905 return true;
1906 }
1907
1908 // ecma6.0 6.2.4.5 ToPropertyDescriptor ( Obj )
ToPropertyDescriptor(JSThread * thread,const JSHandle<JSTaggedValue> & obj,PropertyDescriptor & desc)1909 void JSObject::ToPropertyDescriptor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc)
1910 {
1911 if (!obj->IsECMAObject()) {
1912 // 2. If Type(Obj) is not Object, throw a TypeError exception.
1913 THROW_TYPE_ERROR(thread, "ToPropertyDescriptor error obj is not Object");
1914 }
1915
1916 if (ToPropertyDescriptorFast(thread, obj, desc)) {
1917 return;
1918 }
1919 auto globalConst = thread->GlobalConstants();
1920 // 3. Let desc be a new Property Descriptor that initially has no fields.
1921 // 4. Let hasEnumerable be HasProperty(Obj, "enumerable")
1922 {
1923 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetEnumerableString());
1924 if (op.IsFound()) {
1925 auto value = op.FastGetValue();
1926 bool enumerable = value->IsException() ? false : value->ToBoolean();
1927 desc.SetEnumerable(enumerable);
1928 }
1929 }
1930 // 7. Let hasConfigurable be HasProperty(Obj, "configurable").
1931 {
1932 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetConfigurableString());
1933 if (op.IsFound()) {
1934 auto value = op.FastGetValue();
1935 bool conf = value->IsException() ? false : value->ToBoolean();
1936 desc.SetConfigurable(conf);
1937 }
1938 }
1939 // 10. Let hasValue be HasProperty(Obj, "value").
1940 {
1941 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetValueString());
1942 if (op.IsFound()) {
1943 JSHandle<JSTaggedValue> prop = op.FastGetValue();
1944 desc.SetValue(prop);
1945 }
1946 }
1947 // 13. Let hasWritable be HasProperty(Obj, "writable").
1948 {
1949 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetWritableString());
1950 if (op.IsFound()) {
1951 auto value = op.FastGetValue();
1952 bool writable = value->IsException() ? false : value->ToBoolean();
1953 desc.SetWritable(writable);
1954 }
1955 }
1956 // 16. Let hasGet be HasProperty(Obj, "get").
1957 {
1958 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetGetString());
1959 if (op.IsFound()) {
1960 JSHandle<JSTaggedValue> getter = op.FastGetValue();
1961 if (!getter->IsCallable() && !getter->IsUndefined()) {
1962 THROW_TYPE_ERROR(thread, "getter not callable or undefined");
1963 }
1964 desc.SetGetter(getter);
1965 }
1966 }
1967
1968 // 19. Let hasSet be HasProperty(Obj, "set").
1969 {
1970 ObjectOperator op(thread, obj.GetTaggedValue(), globalConst->GetSetString());
1971 if (op.IsFound()) {
1972 JSHandle<JSTaggedValue> setter = op.FastGetValue();
1973 if (!setter->IsCallable() && !setter->IsUndefined()) {
1974 THROW_TYPE_ERROR(thread, "setter not callable or undefined");
1975 }
1976 desc.SetSetter(setter);
1977 }
1978 }
1979
1980 // 22. If either desc.[[Get]] or desc.[[Set]] is present, then
1981 if (desc.IsAccessorDescriptor()) {
1982 // 22a. If either desc.[[Value]] or desc.[[Writable]] is present, throw a TypeError exception.
1983 if (desc.HasValue() || desc.HasWritable()) {
1984 THROW_TYPE_ERROR(thread, "either desc.[[Value]] or desc.[[Writable]] is present");
1985 }
1986 }
1987 // 23. Return desc.
1988 }
1989
SpeciesConstructor(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & defaultConstructort)1990 JSHandle<JSTaggedValue> JSObject::SpeciesConstructor(JSThread *thread, const JSHandle<JSObject> &obj,
1991 const JSHandle<JSTaggedValue> &defaultConstructort)
1992 {
1993 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1994 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
1995 // Assert: Type(O) is Object.
1996 ASSERT_PRINT(obj->IsECMAObject(), "obj must be js object");
1997
1998 // Let C be Get(O, "constructor").
1999 JSHandle<JSTaggedValue> contructorKey = globalConst->GetHandledConstructorString();
2000 JSHandle<JSTaggedValue> objConstructor(JSTaggedValue::GetProperty(thread, JSHandle<JSTaggedValue>(obj),
2001 contructorKey).GetValue());
2002 // ReturnIfAbrupt(C).
2003 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
2004 // If C is undefined, return defaultConstructor.
2005 if (objConstructor->IsUndefined()) {
2006 return defaultConstructort;
2007 }
2008 // If Type(C) is not Object, throw a TypeError exception.
2009 if (!objConstructor->IsECMAObject()) {
2010 THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is not Object",
2011 JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
2012 }
2013 // Let S be Get(C, @@species).
2014 JSHandle<JSTaggedValue> speciesSymbol = env->GetSpeciesSymbol();
2015 JSHandle<JSTaggedValue> speciesConstructor(GetProperty(thread, objConstructor, speciesSymbol).GetValue());
2016 // ReturnIfAbrupt(S).
2017 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
2018 // If S is either undefined or null, return defaultConstructor.
2019 if (speciesConstructor->IsUndefined() || speciesConstructor->IsNull()) {
2020 return defaultConstructort;
2021 }
2022 // If IsConstructor(S) is true, return S.
2023 if (speciesConstructor->IsConstructor()) {
2024 return speciesConstructor;
2025 }
2026 // Throw a TypeError exception.
2027 THROW_TYPE_ERROR_AND_RETURN(thread, "Is not Constructor",
2028 JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
2029 return JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception());
2030 }
2031
2032 // 6.2.4.6 CompletePropertyDescriptor ( Desc )
CompletePropertyDescriptor(const JSThread * thread,PropertyDescriptor & desc)2033 void PropertyDescriptor::CompletePropertyDescriptor(const JSThread *thread, PropertyDescriptor &desc)
2034 {
2035 // 1. ReturnIfAbrupt(Desc).
2036 // 2. Assert: Desc is a Property Descriptor
2037 // 3. Let like be Record{[[Value]]: undefined, [[Writable]]: false, [[Get]]: undefined, [[Set]]: undefined,
2038 // [[Enumerable]]: false, [[Configurable]]: false}.
2039 // 4. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then
2040 if (!desc.IsAccessorDescriptor()) {
2041 // a. If Desc does not have a [[Value]] field, set Desc.[[Value]] to like.[[Value]].
2042 // b. If Desc does not have a [[Writable]] field, set Desc.[[Writable]] to like.[[Writable]].
2043 if (!desc.HasValue()) {
2044 desc.SetValue(JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
2045 }
2046 if (!desc.HasWritable()) {
2047 desc.SetWritable(false);
2048 }
2049 } else {
2050 // a. If Desc does not have a [[Get]] field, set Desc.[[Get]] to like.[[Get]].
2051 // b. If Desc does not have a [[Set]] field, set Desc.[[Set]] to like.[[Set]].
2052 // Default value of Get and Set is undefined.
2053 }
2054 // 6. If Desc does not have an [[Enumerable]] field, set Desc.[[Enumerable]] to like.[[Enumerable]].
2055 // 7. If Desc does not have a [[Configurable]] field, set Desc.[[Configurable]] to like.[[Configurable]].
2056 if (!desc.HasEnumerable()) {
2057 desc.SetEnumerable(false);
2058 }
2059 if (!desc.HasConfigurable()) {
2060 desc.SetConfigurable(false);
2061 }
2062 }
2063
2064 // 13.7.5.15 EnumerateObjectProperties ( O )
EnumerateObjectProperties(JSThread * thread,const JSHandle<JSTaggedValue> & obj)2065 JSHandle<JSForInIterator> JSObject::EnumerateObjectProperties(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
2066 {
2067 // 1. Return an Iterator object (25.1.1.2) whose next method iterates over all the String-valued keys of
2068 // enumerable properties of O. The Iterator object must inherit from %IteratorPrototype% (25.1.2). The
2069 // mechanics and order of enumerating the properties is not specified but must conform to the rules specified
2070 // below.
2071 JSHandle<JSTaggedValue> object;
2072 if (obj->IsString()) {
2073 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2074 object = JSHandle<JSTaggedValue>::Cast(JSPrimitiveRef::StringCreate(thread, obj, undefined));
2075 } else {
2076 object = JSTaggedValue::ToPrototypeOrObj(thread, obj);
2077 }
2078
2079 return thread->GetEcmaVM()->GetFactory()->NewJSForinIterator(object);
2080 }
2081
DefinePropertyByLiteral(JSThread * thread,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool useForClass)2082 void JSObject::DefinePropertyByLiteral(JSThread *thread, const JSHandle<JSObject> &obj,
2083 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
2084 bool useForClass)
2085 {
2086 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
2087 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2088 PropertyAttributes attr = useForClass ? PropertyAttributes::Default(true, false, true)
2089 : PropertyAttributes::Default();
2090
2091 if (value->IsAccessorData()) {
2092 attr.SetIsAccessor(true);
2093 }
2094
2095 uint32_t index = 0;
2096 if (UNLIKELY(JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
2097 AddElementInternal(thread, obj, index, value, attr);
2098 return;
2099 }
2100 LOG_ECMA(FATAL) << "this branch is unreachable";
2101 UNREACHABLE();
2102 }
2103
DefineSetter(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)2104 void JSObject::DefineSetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2105 const JSHandle<JSTaggedValue> &value)
2106 {
2107 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2108 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2109 ObjectOperator op(thread, obj, key, OperatorType::OWN);
2110 ASSERT(op.IsFound());
2111 op.DefineSetter(value);
2112 }
2113
DefineGetter(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)2114 void JSObject::DefineGetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2115 const JSHandle<JSTaggedValue> &value)
2116 {
2117 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2118 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2119 ObjectOperator op(thread, obj, key, OperatorType::OWN);
2120 ASSERT(op.IsFound());
2121 op.DefineGetter(value);
2122 }
2123
CreateObjectFromProperties(const JSThread * thread,const JSHandle<TaggedArray> & properties,JSTaggedValue ihcVal)2124 JSHandle<JSObject> JSObject::CreateObjectFromProperties(const JSThread *thread, const JSHandle<TaggedArray> &properties,
2125 JSTaggedValue ihcVal)
2126 {
2127 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2128 size_t length = properties->GetLength();
2129 uint32_t propsLen = 0;
2130 for (size_t i = 0; i < length; i += 2) { // 2: skip a pair of key and value
2131 if (properties->Get(i).IsHole()) {
2132 break;
2133 }
2134 propsLen++;
2135 }
2136 if (propsLen <= PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES) {
2137 JSHandle<JSObject> obj = factory->NewOldSpaceObjLiteralByHClass(properties, propsLen);
2138 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
2139 if (ihcVal.IsJSHClass()) {
2140 bool isSuccess = true;
2141 JSHClass *ihc = JSHClass::Cast(ihcVal.GetTaggedObject());
2142 JSHClass *oldHC = obj->GetJSHClass();
2143 ihc->SetPrototype(thread, oldHC->GetPrototype());
2144 obj->SetClass(ihc);
2145 for (size_t i = 0; i < propsLen; i++) {
2146 auto value = obj->ConvertValueWithRep(i, properties->Get(i * 2 + 1));
2147 if (!value.first) {
2148 isSuccess = false;
2149 break;
2150 }
2151 obj->SetPropertyInlinedPropsWithRep(thread, i, value.second);
2152 }
2153 if (isSuccess) {
2154 return obj;
2155 }
2156 // The layout representation of ihc is inaccurate and needs to be rolled back to the old HClass
2157 obj->SetClass(oldHC);
2158 }
2159 for (size_t i = 0; i < propsLen; i++) {
2160 // 2: literal contains a pair of key-value
2161 obj->SetPropertyInlinedProps(thread, i, properties->Get(i * 2 + 1));
2162 }
2163 return obj;
2164 } else {
2165 JSHandle<JSObject> obj = factory->NewEmptyJSObject();
2166 JSHClass::TransitionToDictionary(thread, obj);
2167
2168 JSMutableHandle<NameDictionary> dict(
2169 thread, NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(propsLen)));
2170 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
2171 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
2172 for (size_t i = 0; i < propsLen; i++) {
2173 PropertyAttributes attr = PropertyAttributes::Default();
2174 // 2: literal contains a pair of key-value
2175 valueHandle.Update(properties->Get(i * 2 + 1));
2176 // 2: literal contains a pair of key-value
2177 keyHandle.Update(properties->Get(i * 2));
2178 JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
2179 dict.Update(newDict);
2180 }
2181 obj->SetProperties(thread, dict);
2182 return obj;
2183 }
2184 }
2185
AddAccessor(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<AccessorData> & value,PropertyAttributes attr)2186 void JSObject::AddAccessor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
2187 const JSHandle<AccessorData> &value, PropertyAttributes attr)
2188 {
2189 ASSERT_PRINT(!(obj->IsUndefined() || obj->IsNull() || obj->IsHole()), "Obj is not a valid object");
2190 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
2191 ASSERT_PRINT(attr.IsAccessor(), "Attr is not AccessorData");
2192 ObjectOperator op(thread, obj, key, OperatorType::OWN);
2193 ASSERT(!op.IsFound());
2194 op.AddProperty(JSHandle<JSObject>::Cast(obj), JSHandle<JSTaggedValue>(value), attr);
2195 }
2196
UpdatePropertyInDictionary(const JSThread * thread,JSTaggedValue key,JSTaggedValue value)2197 bool JSObject::UpdatePropertyInDictionary(const JSThread *thread, JSTaggedValue key, JSTaggedValue value)
2198 {
2199 [[maybe_unused]] DisallowGarbageCollection noGc;
2200 NameDictionary *dict = NameDictionary::Cast(GetProperties().GetTaggedObject());
2201 int entry = dict->FindEntry(key);
2202 if (entry == -1) {
2203 return false;
2204 }
2205 dict->UpdateValue(thread, entry, value);
2206 return true;
2207 }
2208
2209 // The hash field may be a hash value, FunctionExtraInfo(JSNativePointer) or TaggedArray
SetHash(int32_t hash)2210 void ECMAObject::SetHash(int32_t hash)
2211 {
2212 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2213 JSTaggedValue value(hashField);
2214 if (value.IsHeapObject()) {
2215 JSThread *thread = this->GetJSThread();
2216 // Hash position reserve in advance.
2217 if (value.IsTaggedArray()) {
2218 TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2219 array->Set(thread, array->GetExtraLength() + HASH_INDEX, JSTaggedValue(hash));
2220 } else if (value.IsNativePointer()) { // FunctionExtraInfo
2221 JSHandle<TaggedArray> newArray =
2222 thread->GetEcmaVM()->GetFactory()->NewTaggedArray(RESOLVED_MAX_SIZE);
2223 newArray->SetExtraLength(0);
2224 newArray->Set(thread, HASH_INDEX, JSTaggedValue(hash));
2225 newArray->Set(thread, FUNCTION_EXTRA_INDEX, value);
2226 Barriers::SetObject<true>(thread, this, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2227 } else {
2228 LOG_ECMA(FATAL) << "this branch is unreachable";
2229 UNREACHABLE();
2230 }
2231 } else {
2232 Barriers::SetPrimitive<JSTaggedType>(this, HASH_OFFSET, JSTaggedValue(hash).GetRawData());
2233 }
2234 }
2235
GetHash() const2236 int32_t ECMAObject::GetHash() const
2237 {
2238 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2239 JSTaggedValue value(hashField);
2240 if (value.IsHeapObject()) {
2241 if (value.IsTaggedArray()) {
2242 TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2243 return array->Get(array->GetExtraLength() + HASH_INDEX).GetInt();
2244 } else {
2245 // Default is 0
2246 return 0;
2247 }
2248 }
2249 JSThread *thread = this->GetJSThread();
2250 JSHandle<JSTaggedValue> valueHandle(thread, value);
2251 return JSTaggedValue::ToInt32(thread, valueHandle);
2252 }
2253
HasHash() const2254 bool ECMAObject::HasHash() const
2255 {
2256 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2257 JSTaggedValue value(hashField);
2258 if (value.IsInt() && value.GetInt() == 0) {
2259 return false;
2260 }
2261 return true;
2262 }
2263
GetNativePointerField(int32_t index) const2264 void *ECMAObject::GetNativePointerField(int32_t index) const
2265 {
2266 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2267 JSTaggedValue value(hashField);
2268 if (value.IsTaggedArray()) {
2269 JSThread *thread = this->GetJSThread();
2270 JSHandle<TaggedArray> array(thread, value);
2271 if (static_cast<int32_t>(array->GetExtraLength()) > index) {
2272 JSHandle<JSNativePointer> pointer(thread, array->Get(index));
2273 return pointer->GetExternalPointer();
2274 }
2275 }
2276 return nullptr;
2277 }
2278
SetNativePointerField(int32_t index,void * nativePointer,const DeleteEntryPoint & callBack,void * data,size_t nativeBindingsize)2279 void ECMAObject::SetNativePointerField(int32_t index, void *nativePointer,
2280 const DeleteEntryPoint &callBack, void *data, size_t nativeBindingsize)
2281 {
2282 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2283 JSTaggedValue value(hashField);
2284 if (value.IsTaggedArray()) {
2285 JSThread *thread = this->GetJSThread();
2286 JSHandle<TaggedArray> array(thread, value);
2287 if (static_cast<int32_t>(array->GetExtraLength()) > index) {
2288 EcmaVM *vm = thread->GetEcmaVM();
2289 JSHandle<JSTaggedValue> current = JSHandle<JSTaggedValue>(thread, array->Get(thread, index));
2290 if (!current->IsHole() && nativePointer == nullptr) {
2291 // Try to remove native pointer if exists.
2292 vm->RemoveFromNativePointerList(*JSHandle<JSNativePointer>(current));
2293 array->Set(thread, index, JSTaggedValue::Hole());
2294 } else {
2295 JSHandle<JSNativePointer> pointer = vm->GetFactory()->NewJSNativePointer(
2296 nativePointer, callBack, data, false, nativeBindingsize);
2297 array->Set(thread, index, pointer.GetTaggedValue());
2298 }
2299 }
2300 }
2301 }
2302
GetNativePointerFieldCount() const2303 int32_t ECMAObject::GetNativePointerFieldCount() const
2304 {
2305 int32_t len = 0;
2306 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2307 JSTaggedValue value(hashField);
2308 if (value.IsTaggedArray()) {
2309 TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
2310 len = static_cast<int32_t>(array->GetExtraLength());
2311 }
2312 return len;
2313 }
2314
SetNativePointerFieldCount(int32_t count)2315 void ECMAObject::SetNativePointerFieldCount(int32_t count)
2316 {
2317 if (count == 0) {
2318 return;
2319 }
2320 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
2321 JSThread *thread = this->GetJSThread();
2322 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(hashField));
2323 JSHandle<ECMAObject> obj(thread, this);
2324 if (value->IsHeapObject()) {
2325 if (value->IsTaggedArray()) {
2326 JSHandle<TaggedArray> array(value);
2327 // Native Pointer field count is fixed.
2328 if (array->GetExtraLength() == 0) {
2329 JSHandle<TaggedArray> newArray =
2330 thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + RESOLVED_MAX_SIZE);
2331 newArray->SetExtraLength(count);
2332 newArray->Set(thread, count + HASH_INDEX, array->Get(HASH_INDEX));
2333 newArray->Set(thread, count + FUNCTION_EXTRA_INDEX, array->Get(FUNCTION_EXTRA_INDEX));
2334 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2335 }
2336 } else if (value->IsJSNativePointer()) {
2337 JSHandle<TaggedArray> newArray =
2338 thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + RESOLVED_MAX_SIZE);
2339 newArray->SetExtraLength(count);
2340 newArray->Set(thread, count + HASH_INDEX, JSTaggedValue(0));
2341 newArray->Set(thread, count + FUNCTION_EXTRA_INDEX, value);
2342 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2343 } else {
2344 LOG_ECMA(FATAL) << "this branch is unreachable";
2345 UNREACHABLE();
2346 }
2347 } else {
2348 JSHandle<TaggedArray> newArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(count + 1);
2349 newArray->SetExtraLength(count);
2350 newArray->Set(thread, count + HASH_INDEX, value);
2351 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
2352 }
2353 }
2354 } // namespace panda::ecmascript
2355