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