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 #ifndef ECMASCRIPT_JSOBJECT_H 17 #define ECMASCRIPT_JSOBJECT_H 18 19 #include "ecmascript/ecma_macros.h" 20 #include "ecmascript/ecma_vm.h" 21 #include "ecmascript/filter_helper.h" 22 #include "ecmascript/ic/property_box.h" 23 #include "ecmascript/js_handle.h" 24 #include "ecmascript/js_hclass.h" 25 #include "ecmascript/js_tagged_value.h" 26 #include "ecmascript/mem/layout_visitor.h" 27 #include "ecmascript/mem/slots.h" 28 #include "ecmascript/mem/visitor.h" 29 #include "ecmascript/method.h" 30 #include "ecmascript/property_attributes.h" 31 #include "ecmascript/tagged_array.h" 32 33 namespace panda { 34 namespace ecmascript { 35 class ObjectOperator; 36 class JSFunction; 37 class AccessorData; 38 class JSArray; 39 class JSForInIterator; 40 class LexicalEnv; 41 class GlobalEnv; 42 class TaggedQueue; 43 class NumberDictionary; 44 45 namespace builtins { 46 class BuiltinsArkTools; 47 } 48 49 using EnumCacheKind = EnumCache::EnumCacheKind; 50 using SCheckMode = JSShared::SCheckMode; 51 52 // Integrity level for objects 53 enum IntegrityLevel { SEALED, FROZEN }; 54 55 enum PositionKind { UNKNOWN = 0, INDEXED_PROPERTY = 1, INLINE_NAMED_PROPERTY = 2, OUT_NAMED_PROPERTY = 3 }; 56 enum PropertyKind { KEY = 0, VALUE, KEY_VALUE }; 57 58 // ecma6.0 6.2.4 The Property Descriptor Specification Type 59 class PropertyDescriptor final { 60 public: 61 PropertyDescriptor() = delete; 62 63 ~PropertyDescriptor() = default; 64 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyDescriptor); 65 DEFAULT_COPY_SEMANTIC(PropertyDescriptor); 66 PropertyDescriptor(const JSThread *thread)67 explicit PropertyDescriptor(const JSThread *thread) : thread_(thread) {} 68 PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v)69 PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v) : thread_(thread), value_(v) {} 70 PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v, bool w, bool e, bool c)71 PropertyDescriptor(const JSThread *thread, JSHandle<JSTaggedValue> v, bool w, bool e, bool c) 72 : thread_(thread), 73 writable_(w), 74 enumerable_(e), 75 configurable_(c), 76 hasWritable_(true), 77 hasEnumerable_(true), 78 hasConfigurable_(true), 79 value_(v) 80 { 81 } 82 PropertyDescriptor(const JSThread *thread, bool w, bool e, bool c)83 PropertyDescriptor(const JSThread *thread, bool w, bool e, bool c) 84 : PropertyDescriptor(thread, JSHandle<JSTaggedValue>(), w, e, c) 85 { 86 } 87 GetValue() const88 inline JSHandle<JSTaggedValue> GetValue() const 89 { 90 if (value_.IsEmpty()) { 91 return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()); 92 } 93 return value_; 94 } 95 GetKey() const96 inline JSHandle<JSTaggedValue> GetKey() const 97 { 98 if (key_.IsEmpty()) { 99 return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()); 100 } 101 return key_; 102 } 103 SetValue(JSHandle<JSTaggedValue> value)104 inline void SetValue(JSHandle<JSTaggedValue> value) 105 { 106 value_ = value; 107 } 108 SetKey(JSHandle<JSTaggedValue> key)109 inline void SetKey(JSHandle<JSTaggedValue> key) 110 { 111 key_ = key; 112 } 113 SetSharedFieldType(SharedFieldType fieldType)114 inline void SetSharedFieldType(SharedFieldType fieldType) 115 { 116 fieldType_ = fieldType; 117 } 118 GetSharedFieldType() const119 inline SharedFieldType GetSharedFieldType() const 120 { 121 return fieldType_; 122 } 123 IsWritable() const124 inline bool IsWritable() const 125 { 126 return writable_; 127 } 128 SetWritable(bool flag)129 inline void SetWritable(bool flag) 130 { 131 writable_ = flag; 132 hasWritable_ = true; 133 } 134 IsEnumerable() const135 inline bool IsEnumerable() const 136 { 137 return enumerable_; 138 } 139 SetEnumerable(bool flag)140 inline void SetEnumerable(bool flag) 141 { 142 enumerable_ = flag; 143 hasEnumerable_ = true; 144 } 145 IsConfigurable() const146 inline bool IsConfigurable() const 147 { 148 return configurable_; 149 } 150 SetConfigurable(bool flag)151 inline void SetConfigurable(bool flag) 152 { 153 configurable_ = flag; 154 hasConfigurable_ = true; 155 } 156 HasValue() const157 inline bool HasValue() const 158 { 159 return !value_.IsEmpty(); 160 } 161 HasWritable() const162 inline bool HasWritable() const 163 { 164 return hasWritable_; 165 } 166 HasConfigurable() const167 inline bool HasConfigurable() const 168 { 169 return hasConfigurable_; 170 } 171 HasEnumerable() const172 inline bool HasEnumerable() const 173 { 174 return hasEnumerable_; 175 } 176 HasGetter() const177 inline bool HasGetter() const 178 { 179 return !getter_.IsEmpty(); 180 } 181 HasSetter() const182 inline bool HasSetter() const 183 { 184 return !setter_.IsEmpty(); 185 } 186 GetGetter() const187 inline JSHandle<JSTaggedValue> GetGetter() const 188 { 189 if (getter_->IsNull()) { 190 return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()); 191 } 192 return getter_; 193 } 194 GetSetter() const195 inline JSHandle<JSTaggedValue> GetSetter() const 196 { 197 if (setter_->IsNull()) { 198 return JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()); 199 } 200 return setter_; 201 } 202 SetGetter(JSHandle<JSTaggedValue> value)203 inline void SetGetter(JSHandle<JSTaggedValue> value) 204 { 205 getter_ = value; 206 } 207 SetSetter(JSHandle<JSTaggedValue> value)208 inline void SetSetter(JSHandle<JSTaggedValue> value) 209 { 210 setter_ = value; 211 } 212 213 // 6.2.4.1 IsAccessorDescriptor() const214 inline bool IsAccessorDescriptor() const 215 { 216 // 2. If both Desc.[[Get]] and Desc.[[Set]] are absent, return false. 217 return !(getter_.IsEmpty() && setter_.IsEmpty()); 218 } 219 IsDataDescriptor() const220 inline bool IsDataDescriptor() const 221 { 222 // 2. If both Desc.[[Value]] and Desc.[[Writable]] are absent, return false. 223 return !(value_.IsEmpty() && !hasWritable_); 224 } 225 IsGenericDescriptor() const226 inline bool IsGenericDescriptor() const 227 { 228 // 2. If IsAccessorDescriptor(Desc) and IsDataDescriptor(Desc) are both false, return true 229 return !IsAccessorDescriptor() && !IsDataDescriptor(); 230 } 231 IsEmpty() const232 inline bool IsEmpty() const 233 { 234 return !hasWritable_ && !hasEnumerable_ && !hasConfigurable_ && !HasValue() && !HasGetter() && !HasSetter(); 235 } 236 237 static void CompletePropertyDescriptor(const JSThread *thread, PropertyDescriptor &desc); 238 239 private: 240 const JSThread *thread_{nullptr}; 241 242 bool writable_ {false}; 243 bool enumerable_ {false}; 244 bool configurable_ {false}; 245 bool hasWritable_ {false}; 246 bool hasEnumerable_ {false}; 247 bool hasConfigurable_ {false}; 248 SharedFieldType fieldType_ {SharedFieldType::NONE}; 249 250 JSHandle<JSTaggedValue> value_ {}; 251 JSHandle<JSTaggedValue> getter_ {}; 252 JSHandle<JSTaggedValue> setter_ {}; 253 JSHandle<JSTaggedValue> key_ {}; 254 }; 255 256 enum class ElementTypes { ALLTYPES, STRING_AND_SYMBOL }; 257 258 class PropertyMetaData { 259 public: 260 using IsFoundField = BitField<bool, 0, 1>; 261 using IsInlinedPropsField = IsFoundField::NextFlag; 262 // 3: The bit field that represents the "Representation" of the property 263 using RepresentationField = IsInlinedPropsField::NextField<Representation, 3>; 264 using OffsetField = RepresentationField::NextField<uint32_t, PropertyAttributes::OFFSET_BITFIELD_NUM>; 265 PropertyMetaData(uint32_t metaData)266 explicit PropertyMetaData(uint32_t metaData) : metaData_(metaData) {} 267 268 ~PropertyMetaData() = default; 269 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyMetaData); 270 DEFAULT_COPY_SEMANTIC(PropertyMetaData); 271 PropertyMetaData(bool isFound)272 explicit PropertyMetaData(bool isFound) 273 { 274 SetFound(isFound); 275 } 276 IsFound() const277 inline bool IsFound() const 278 { 279 return IsFoundField::Get(metaData_); 280 } 281 SetFound(bool flag)282 inline void SetFound(bool flag) 283 { 284 IsFoundField::Set(flag, &metaData_); 285 } 286 GetIsInlinedProps() const287 inline bool GetIsInlinedProps() const 288 { 289 return IsInlinedPropsField::Get(metaData_); 290 } 291 SetIsInlinedProps(bool flag)292 inline void SetIsInlinedProps(bool flag) 293 { 294 IsInlinedPropsField::Set(flag, &metaData_); 295 } 296 GetRepresentation() const297 inline Representation GetRepresentation() const 298 { 299 return RepresentationField::Get(metaData_); 300 } 301 SetRepresentation(Representation representation)302 inline void SetRepresentation(Representation representation) 303 { 304 RepresentationField::Set<uint32_t>(representation, &metaData_); 305 } 306 SetOffset(uint32_t offset)307 inline void SetOffset(uint32_t offset) 308 { 309 OffsetField::Set<uint32_t>(offset, &metaData_); 310 } 311 GetOffset() const312 inline uint32_t GetOffset() const 313 { 314 return OffsetField::Get(metaData_); 315 } 316 317 private: 318 uint32_t metaData_{0}; 319 }; 320 321 class OperationResult { 322 public: OperationResult(const JSThread *thread, JSTaggedValue value, PropertyMetaData metaData)323 OperationResult(const JSThread *thread, JSTaggedValue value, PropertyMetaData metaData) 324 : metaData_(metaData) 325 { 326 thread_ = thread; 327 value_ = JSHandle<JSTaggedValue>(thread_, value); 328 } 329 330 ~OperationResult() = default; 331 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(OperationResult); 332 DEFAULT_COPY_SEMANTIC(OperationResult); 333 GetValue() const334 JSHandle<JSTaggedValue> GetValue() const 335 { 336 if (value_->IsPropertyBox()) { 337 return JSHandle<JSTaggedValue>(thread_, 338 PropertyBox::Cast(value_.GetTaggedValue().GetTaggedObject())->GetValue()); 339 } 340 return value_; 341 } 342 GetRawValue() const343 JSHandle<JSTaggedValue> GetRawValue() const 344 { 345 return value_; 346 } 347 GetPropertyMetaData() const348 const PropertyMetaData &GetPropertyMetaData() const 349 { 350 return metaData_; 351 } 352 353 private: 354 const JSThread *thread_ {nullptr}; 355 JSHandle<JSTaggedValue> value_ {}; 356 PropertyMetaData metaData_ {0U}; 357 }; 358 359 360 // HashField possible layout: 361 // [ hashValue ] | [extraInfo] | [ hashValue, extraInfo, nativePointer, ... ] 362 // nativePointer number depends on the extraLength of taggedArray 363 class ECMAObject : public TaggedObject { 364 public: 365 static constexpr int HASH_INDEX = 0; 366 static constexpr int FUNCTION_EXTRA_INDEX = 1; 367 static constexpr int RESOLVED_MAX_SIZE = 2; 368 369 CAST_CHECK(ECMAObject, IsECMAObject); 370 371 void SetCallable(bool flag); 372 bool IsCallable() const; 373 Method *GetCallTarget() const; 374 375 static constexpr size_t HASH_OFFSET = TaggedObjectSize(); 376 static constexpr size_t SIZE = HASH_OFFSET + sizeof(JSTaggedType); 377 378 static void SetHash(const JSThread *thread, int32_t hash, const JSHandle<ECMAObject> &obj); 379 int32_t GetHash() const; 380 bool HasHash() const; 381 InitializeHash()382 void InitializeHash() 383 { 384 Barriers::SetPrimitive<JSTaggedType>(this, ECMAObject::HASH_OFFSET, JSTaggedValue(0).GetRawData()); 385 } 386 387 void* GetNativePointerField(int32_t index) const; 388 void SetNativePointerField(const JSThread *thread, int32_t index, void *nativePointer, 389 const NativePointerCallback &callBack, void *data, size_t nativeBindingsize = 0, 390 Concurrent isConcurrent = Concurrent::NO); 391 int32_t GetNativePointerFieldCount() const; 392 void SetNativePointerFieldCount(const JSThread *thread, int32_t count); 393 394 DECL_VISIT_OBJECT(HASH_OFFSET, SIZE); 395 396 template <VisitType visitType> VisitObjects(const EcmaObjectRangeVisitor &visitor)397 void VisitObjects(const EcmaObjectRangeVisitor &visitor) 398 { 399 // no field in this object 400 VisitRangeSlot<visitType>(visitor); 401 } 402 }; 403 404 class JSObject : public ECMAObject { 405 public: 406 static constexpr int MIN_ELEMENTS_LENGTH = 3; 407 static constexpr int MIN_PROPERTIES_LENGTH = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS; 408 static constexpr int FAST_ELEMENTS_FACTOR = 3; 409 static constexpr int MIN_GAP = 256; 410 static constexpr int MAX_GAP = 1_KB; 411 static constexpr uint32_t MAX_ELEMENT_INDEX = std::numeric_limits<uint32_t>::max(); 412 static constexpr int MIN_ELEMENTS_HINT_LENGTH = 1_KB; 413 static constexpr int MAX_ELEMENTS_HINT_LENGTH = 2_MB; 414 static constexpr int ELEMENTS_HINT_FACTOR = 8; 415 static constexpr int SHOULD_TRANS_TO_FAST_ELEMENTS_FACTOR = 2; 416 417 CAST_CHECK(JSObject, IsECMAObject); 418 419 // ecma6.0 6.2.4.4 420 static JSHandle<JSTaggedValue> FromPropertyDescriptor(JSThread *thread, const PropertyDescriptor &desc); 421 422 // ecma6.0 6.2.4.5 ToPropertyDescriptor ( Obj ) 423 static void ToPropertyDescriptor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, PropertyDescriptor &desc); 424 static bool ToPropertyDescriptorFast(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 425 PropertyDescriptor &desc); 426 427 static JSHandle<JSTaggedValue> CallFunction(JSThread *thread, const JSHandle<JSTaggedValue> &func); 428 429 // ecma6 7.3 Operations on Objects 430 static JSHandle<JSTaggedValue> GetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 431 const JSHandle<JSTaggedValue> &key); 432 433 static JSHandle<JSTaggedValue> FastGetMethod(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 434 const JSHandle<JSTaggedValue> &key); 435 436 static bool CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key, 437 const JSHandle<JSTaggedValue> &value, SCheckMode sCheckMode = SCheckMode::CHECK); 438 439 static bool CreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index, 440 const JSHandle<JSTaggedValue> &value, SCheckMode sCheckMode = SCheckMode::CHECK); 441 442 static bool CreateMethodProperty(JSThread *thread, const JSHandle<JSObject> &obj, 443 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value); 444 445 static bool CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj, 446 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value, 447 SCheckMode sCheckMode = SCheckMode::CHECK); 448 449 static bool CreateDataPropertyOrThrow(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index, 450 const JSHandle<JSTaggedValue> &value, 451 SCheckMode sCheckMode = SCheckMode::CHECK); 452 453 static JSHandle<TaggedArray> PUBLIC_API EnumerableOwnNames(JSThread *thread, const JSHandle<JSObject> &obj); 454 455 // 7.3.23 EnumerableOwnPropertyNames ( O, kind ) 456 static JSHandle<TaggedArray> EnumerableOwnPropertyNames(JSThread *thread, const JSHandle<JSObject> &obj, 457 PropertyKind kind); 458 static void EnumerableOwnPropertyNamesHelper(JSThread *thread, const JSHandle<JSObject> &obj, 459 const JSHandle<TaggedArray> &arr, JSHandle<TaggedArray> &properties, 460 uint32_t &index, bool &fastMode, PropertyKind kind); 461 462 static JSHandle<GlobalEnv> GetFunctionRealm(JSThread *thread, const JSHandle<JSTaggedValue> &object); 463 464 static bool SetIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level); 465 466 static bool FreezeSharedObject(JSThread *thread, const JSHandle<JSObject> &obj); 467 468 static bool TestIntegrityLevel(JSThread *thread, const JSHandle<JSObject> &obj, IntegrityLevel level); 469 470 static JSHandle<JSTaggedValue> SpeciesConstructor(JSThread *thread, const JSHandle<JSObject> &obj, 471 const JSHandle<JSTaggedValue> &defaultConstructor); 472 static JSHandle<JSTaggedValue> SlowSpeciesConstructor(JSThread *thread, 473 const JSHandle<JSTaggedValue> &objConstructor, 474 const JSHandle<JSTaggedValue> &defaultConstructor); 475 // 7.3.17 476 template<ElementTypes types = ElementTypes::ALLTYPES> 477 static JSHandle<JSTaggedValue> CreateListFromArrayLike(JSThread *thread, const JSHandle<JSTaggedValue> &obj); 478 479 // ecma6 9.1 480 // [[GetPrototypeOf]] 481 static JSTaggedValue GetPrototype(const JSHandle<JSObject> &obj); 482 483 static JSTaggedValue GetPrototype(JSTaggedValue obj); 484 485 // [[SetPrototypeOf]] 486 static bool SetPrototype(JSThread *thread, const JSHandle<JSObject> &obj, 487 const JSHandle<JSTaggedValue> &proto, 488 bool isChangeProto = false); 489 490 // [[IsExtensible]] 491 bool IsExtensible() const; 492 493 // [[PreventExtensions]] 494 static bool PreventExtensions(JSThread *thread, const JSHandle<JSObject> &obj); 495 496 // [[GetOwnProperty]] -> Undefined | Property Descriptor 497 static bool GetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key, 498 PropertyDescriptor &desc); 499 500 static bool GlobalGetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc); 501 502 static bool OrdinaryGetOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, 503 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc); 504 505 // [[DefineOwnProperty]] 506 static bool DefineOwnProperty(JSThread *thread, ObjectOperator *op, 507 const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK); 508 509 static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key, 510 const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK); 511 512 static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index, 513 const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK); 514 515 static bool OrdinaryDefineOwnProperty(JSThread *thread, ObjectOperator *op, 516 const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK); 517 518 static bool OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, 519 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc, 520 SCheckMode sCheckMode = SCheckMode::CHECK); 521 522 static bool OrdinaryDefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index, 523 const PropertyDescriptor &desc, 524 SCheckMode sCheckMode = SCheckMode::CHECK); 525 526 static bool IsCompatiblePropertyDescriptor(bool extensible, const PropertyDescriptor &desc, 527 const PropertyDescriptor ¤t); 528 529 static bool ValidateAndApplyPropertyDescriptor(ObjectOperator *op, bool extensible, const PropertyDescriptor &desc, 530 const PropertyDescriptor ¤t, 531 SCheckMode sCheckMode = SCheckMode::CHECK); 532 533 static OperationResult PUBLIC_API GetProperty(JSThread *thread, const JSHandle<JSObject> &obj, 534 const JSHandle<JSTaggedValue> &key); 535 536 static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 537 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver); 538 539 static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 540 const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode = SCheckMode::CHECK); 541 542 static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index); 543 544 static OperationResult GetPropertyFromGlobal(JSThread *thread, const JSHandle<JSTaggedValue> &key); 545 546 static bool SetProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key, 547 const JSHandle<JSTaggedValue> &value, bool mayThrow = false); 548 549 static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key, 550 const JSHandle<JSTaggedValue> &value, bool mayThrow = false, 551 SCheckMode checkMode = SCheckMode::CHECK); 552 553 static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key, 554 const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &receiver, 555 bool mayThrow = false); 556 557 static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index, 558 const JSHandle<JSTaggedValue> &value, bool mayThrow = false); 559 560 static bool GlobalSetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key, 561 const JSHandle<JSTaggedValue> &value, bool mayThrow); 562 563 // [[HasProperty]] 564 static bool HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key); 565 566 static bool HasProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index); 567 568 // 9.1.10 [[Delete]] 569 static bool DeleteProperty(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key, 570 SCheckMode sCheckMode = SCheckMode::CHECK); 571 572 // [[OwnPropertyKeys]] 573 static JSHandle<TaggedArray> GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj); 574 575 static JSHandle<TaggedArray> GetAllPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t filter); 576 577 static void CollectEnumKeysAlongProtoChain(JSThread *thread, const JSHandle<JSObject> &obj, 578 JSHandle<TaggedArray> keyArray, uint32_t *keys, 579 JSHandle<TaggedQueue> shadowQueue, int32_t lastLength = -1); 580 581 static void AppendOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj, 582 JSHandle<TaggedArray> keyArray, uint32_t *keys, 583 JSHandle<TaggedQueue> shadowQueue); 584 585 static JSHandle<TaggedArray> GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSObject> &obj); 586 587 // 9.1.13 ObjectCreate 588 static JSHandle<JSObject> ObjectCreate(JSThread *thread, const JSHandle<JSObject> &proto); 589 590 // 12.9.4 Runtime Semantics: InstanceofOperator(O, C) 591 static bool InstanceOf(JSThread *thread, const JSHandle<JSTaggedValue> &object, 592 const JSHandle<JSTaggedValue> &target); 593 594 static JSTaggedValue TryGetEnumCache(JSThread *thread, JSTaggedValue obj); 595 596 // 13.7.5.15 EnumerateObjectProperties ( O ); same as [[Enumerate]] 597 static JSHandle<JSForInIterator> EnumerateObjectProperties(JSThread *thread, const JSHandle<JSTaggedValue> &obj); 598 static JSHandle<JSForInIterator> LoadEnumerateProperties(JSThread *thread, const JSHandle<JSTaggedValue> &object); 599 600 static bool IsRegExp(JSThread *thread, const JSHandle<JSTaggedValue> &argument); 601 602 static JSTaggedValue CallGetter(JSThread *thread, const AccessorData *accessor, 603 const JSHandle<JSTaggedValue> &receiver); 604 static bool PUBLIC_API CallSetter(JSThread *thread, const AccessorData &accessor, 605 const JSHandle<JSTaggedValue> &receiver, 606 const JSHandle<JSTaggedValue> &value, bool mayThrow = false); 607 608 void FillElementsWithHoles(const JSThread *thread, uint32_t start, uint32_t end); 609 GetJSHClass() const610 JSHClass *GetJSHClass() const 611 { 612 return GetClass(); 613 } 614 uint32_t GetNonInlinedFastPropsCapacity() const; 615 bool IsJSGlobalObject() const; 616 bool IsConstructor() const; 617 bool IsECMAObject() const; 618 bool IsJSError() const; 619 bool IsArguments() const; 620 bool IsDate() const; 621 bool IsJSArray() const; 622 bool IsJSSArray() const; 623 bool IsJSShared() const; 624 bool IsJSMap() const; 625 bool IsJSSet() const; 626 bool IsJSRegExp() const; 627 bool IsJSFunction() const; 628 bool IsBoundFunction() const; 629 bool IsJSIntlBoundFunction() const; 630 bool IsProxyRevocFunction() const; 631 bool IsAccessorData() const; 632 bool IsJSGlobalEnv() const; 633 bool IsJSProxy() const; 634 bool IsGeneratorObject() const; 635 bool IsAsyncGeneratorObject() const; 636 bool IsForinIterator() const; 637 bool IsJSSetIterator() const; 638 bool IsJSRegExpIterator() const; 639 bool IsJSMapIterator() const; 640 bool IsJSArrayIterator() const; 641 bool IsJSAPIArrayListIterator() const; 642 bool IsJSAPIStackIterator() const; 643 bool IsJSAPIVectorIterator() const; 644 bool IsJSAPIBitVectorIterator() const; 645 bool IsJSAPILinkedListIterator() const; 646 bool IsJSAPIListIterator() const; 647 bool IsJSPrimitiveRef() const; 648 bool IsElementDict() const; 649 bool IsPropertiesDict() const; 650 bool IsTypedArray() const; 651 bool PUBLIC_API ElementsAndPropertiesIsEmpty() const; 652 653 static PUBLIC_API void DefinePropertyByLiteral(JSThread *thread, const JSHandle<JSObject> &obj, 654 const JSHandle<JSTaggedValue> &key, 655 const JSHandle<JSTaggedValue> &value, 656 bool useForClass = false); 657 static void DefineSetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key, 658 const JSHandle<JSTaggedValue> &value); 659 static void DefineGetter(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key, 660 const JSHandle<JSTaggedValue> &value); 661 static PUBLIC_API JSHandle<JSObject> CreateObjectFromProperties(const JSThread *thread, 662 const JSHandle<TaggedArray> &properties, 663 JSTaggedValue ihc = JSTaggedValue::Undefined()); 664 static JSHandle<JSObject> CreateObjectFromProperties(const JSThread *thread, 665 const JSHandle<JSHClass> &hclass, 666 const JSHandle<TaggedArray> &properties, 667 uint32_t propsLen); 668 static JSHandle<JSObject> CreateObjectFromPropertiesByIHClass(const JSThread *thread, 669 const JSHandle<TaggedArray> &properties, 670 uint32_t propsLen, 671 const JSHandle<JSHClass> &ihc); 672 static bool CheckPropertiesForRep( 673 const JSHandle<TaggedArray> &properties, uint32_t propsLen, const JSHandle<JSHClass> &ihc); 674 static void GetAllKeys(const JSThread *thread, const JSHandle<JSObject> &obj, int offset, 675 const JSHandle<TaggedArray> &keyArray); 676 static void GetAllKeysForSerialization(const JSHandle<JSObject> &obj, std::vector<JSTaggedValue> &keyVector); 677 678 static void GetAllKeysByFilter(const JSThread *thread, const JSHandle<JSObject> &obj, 679 uint32_t &keyArrayEffectivelength, 680 const JSHandle<TaggedArray> &keyArray, 681 uint32_t filter); 682 static void GetAllElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset, 683 const JSHandle<TaggedArray> &keyArray); 684 static void GetAllElementKeysByFilter(JSThread *thread, 685 const JSHandle<JSObject> &obj, 686 const JSHandle<TaggedArray> &keyArray, 687 uint32_t &keyArrayEffectiveLength, 688 uint32_t filter); 689 690 static void GetALLElementKeysIntoVector(const JSThread *thread, const JSHandle<JSObject> &obj, 691 std::vector<JSTaggedValue> &keyVector); 692 std::pair<uint32_t, uint32_t> GetNumberOfEnumKeys() const; 693 uint32_t GetNumberOfKeys(); 694 uint32_t GetNumberOfElements(); 695 696 static JSHandle<TaggedArray> GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset, 697 uint32_t numOfElements, uint32_t *keys); 698 static void CollectEnumElementsAlongProtoChain(JSThread *thread, const JSHandle<JSObject> &obj, int offset, 699 JSHandle<TaggedArray> elementArray, uint32_t *keys, 700 int32_t lastLength = -1); 701 static void GetEnumElementKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset, 702 const JSHandle<TaggedArray> &keyArray); 703 static JSHandle<TaggedArray> GetAllEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj, 704 uint32_t numOfKeys, uint32_t *keys); 705 static uint32_t GetAllEnumKeys(JSThread *thread, const JSHandle<JSObject> &obj, int offset, 706 const JSHandle<TaggedArray> &keyArray); 707 708 static void AddAccessor(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key, 709 const JSHandle<AccessorData> &value, PropertyAttributes attr); 710 711 static constexpr size_t PROPERTIES_OFFSET = ECMAObject::SIZE; 712 713 ACCESSORS(Properties, PROPERTIES_OFFSET, ELEMENTS_OFFSET); 714 ACCESSORS(Elements, ELEMENTS_OFFSET, SIZE); 715 716 DECL_VISIT_OBJECT_FOR_JS_OBJECT(ECMAObject, PROPERTIES_OFFSET, SIZE) 717 718 DECL_DUMP() 719 static const CString ExtractConstructorAndRecordName(JSThread *thread, TaggedObject *obj, bool noAllocate = false, 720 bool *isCallGetter = nullptr); 721 722 static JSHandle<NameDictionary> PUBLIC_API TransitionToDictionary(const JSThread *thread, 723 const JSHandle<JSObject> &receiver); 724 725 static inline std::pair<bool, JSTaggedValue> ConvertValueWithRep(PropertyAttributes attr, JSTaggedValue value); 726 727 inline void SetPropertyInlinedPropsWithRep(const JSThread *thread, uint32_t index, JSTaggedValue value); 728 template <bool needBarrier = true> 729 inline void SetPropertyInlinedProps(const JSThread *thread, uint32_t index, JSTaggedValue value); 730 template <bool needBarrier = true> 731 inline void SetPropertyInlinedProps(const JSThread *thread, const JSHClass *hclass, uint32_t index, 732 JSTaggedValue value); 733 inline JSTaggedValue GetPropertyInlinedPropsWithRep(uint32_t index, PropertyAttributes attr) const; 734 inline JSTaggedValue GetPropertyInlinedPropsWithRep(const JSHClass *hclass, uint32_t index, 735 PropertyAttributes attr) const; 736 inline JSTaggedValue GetPropertyInlinedProps(uint32_t index) const; 737 inline JSTaggedValue GetPropertyInlinedProps(const JSHClass *hclass, uint32_t index) const; 738 inline JSTaggedValue GetProperty(const JSHClass *hclass, PropertyAttributes attr) const; 739 PropertyBox* GetGlobalPropertyBox(JSThread *thread, const std::string& key); 740 template <bool needBarrier = true> 741 inline void SetProperty(const JSThread *thread, const JSHClass *hclass, PropertyAttributes attr, 742 JSTaggedValue value); 743 744 static bool IsArrayLengthWritable(JSThread *thread, const JSHandle<JSObject> &receiver); 745 bool UpdatePropertyInDictionary(const JSThread *thread, JSTaggedValue key, JSTaggedValue value); 746 static bool ShouldTransToDict(uint32_t capacity, uint32_t index); 747 static bool ShouldTransToFastElements(JSThread *thread, TaggedArray *elements, uint32_t capacity, uint32_t index); 748 static bool ShouldOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj); 749 static JSHandle<TaggedArray> GrowElementsCapacity(const JSThread *thread, const JSHandle<JSObject> &obj, 750 uint32_t capacity, bool highGrowth = false, bool isNew = false); 751 752 static bool IsDepulicateKeys(JSThread *thread, JSHandle<TaggedArray> keys, int32_t lastLength, 753 JSHandle<TaggedQueue> shadowQueue, JSHandle<JSTaggedValue> key); 754 755 static void SetEnumCacheKind(JSThread *thread, TaggedArray *array, EnumCacheKind kind); 756 static EnumCacheKind GetEnumCacheKind(JSThread *thread, TaggedArray *array); 757 static EnumCacheKind GetEnumCacheKind(JSThread *thread, JSTaggedValue enumCache); 758 759 static void ClearHasDeleteProperty(JSHandle<JSTaggedValue> object); 760 761 static JSHandle<JSTaggedValue> IterableToList(JSThread *thread, const JSHandle<JSTaggedValue> &items, 762 JSTaggedValue method = JSTaggedValue::Undefined()); 763 764 static void TryOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj); 765 static void OptimizeAsFastProperties(const JSThread *thread, JSHandle<JSObject> obj); 766 767 static void SetSProperties(JSThread *thread, JSHandle<JSObject> obj, const std::vector<PropertyDescriptor> &descs); 768 769 static void PUBLIC_API TryMigrateToGenericKindForJSObject(const JSThread *thread, const JSHandle<JSObject> &obj, 770 const ElementsKind oldKind); 771 protected: 772 static void ElementsToDictionary(const JSThread *thread, JSHandle<JSObject> obj); 773 774 private: 775 friend class ObjectOperator; 776 friend class LoadICRuntime; 777 friend class StoreICRuntime; 778 friend class ObjectFastOperator; 779 friend class ICRuntimeStub; 780 friend class RuntimeStubs; 781 friend class JSSharedArray; 782 friend class builtins::BuiltinsArkTools; 783 784 static bool HasMutantTaggedArrayElements(const JSHandle<JSObject> &obj); 785 PropertyBox* GetGlobalPropertyBox(JSTaggedValue key); 786 static bool PUBLIC_API AddElementInternal( 787 JSThread *thread, const JSHandle<JSObject> &receiver, uint32_t index, const JSHandle<JSTaggedValue> &value, 788 PropertyAttributes attr = PropertyAttributes(PropertyAttributes::GetDefaultAttributes())); 789 790 static JSTaggedValue GetProperty(JSThread *thread, ObjectOperator *op); 791 static bool SetProperty(ObjectOperator *op, const JSHandle<JSTaggedValue> &value, bool mayThrow); 792 static void DeletePropertyInternal(JSThread *thread, const JSHandle<JSObject> &obj, 793 const JSHandle<JSTaggedValue> &key, uint32_t index); 794 int FindProperty(const JSHandle<JSTaggedValue> &key); 795 796 static uint32_t ComputeElementCapacity(uint32_t oldCapacity, bool isNew = false); 797 static uint32_t ComputeElementCapacityHighGrowth(uint32_t oldCapacity); 798 static uint32_t ComputeElementCapacityWithHint(uint32_t oldCapacity, uint32_t hint); 799 static uint32_t ComputeNonInlinedFastPropsCapacity(JSThread *thread, uint32_t oldCapacity, 800 uint32_t maxNonInlinedFastPropsCapacity); 801 802 static JSTaggedValue ShouldGetValueFromBox(ObjectOperator *op); 803 static std::pair<JSHandle<TaggedArray>, JSHandle<TaggedArray>> GetOwnEnumerableNamesInFastMode( 804 JSThread *thread, const JSHandle<JSObject> &obj, uint32_t *copyLengthOfKeys, uint32_t *copyLengthOfElements); 805 static bool CheckHClassHit(const JSHandle<JSObject> &obj, const JSHandle<JSHClass> &cls); 806 static uint32_t SetValuesOrEntries(JSThread *thread, const JSHandle<TaggedArray> &prop, uint32_t index, 807 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value, 808 PropertyKind kind); 809 static bool IsSimpleEnumCacheValid(JSTaggedValue receiver); 810 static bool IsEnumCacheWithProtoChainInfoValid(JSTaggedValue receiver); 811 static void TrimInlinePropsSpace(const JSThread *thread, const JSHandle<JSObject> &object, 812 uint32_t numberInlinedProps); 813 static bool ValidateDataDescriptorWhenConfigurable(ObjectOperator *op, const PropertyDescriptor &desc, 814 const PropertyDescriptor ¤t, SCheckMode sCheckMode); 815 static bool SetPropertyForDataDescriptor(ObjectOperator *op, const JSHandle<JSTaggedValue> &value, 816 JSHandle<JSTaggedValue> &receiver, bool mayThrow, bool isInternalAccessor); 817 static bool SetPropertyForDataDescriptorProxy(JSThread *thread, ObjectOperator *op, 818 const JSHandle<JSTaggedValue> &value, 819 JSHandle<JSTaggedValue> &receiver); 820 }; 821 } // namespace ecmascript 822 } // namespace panda 823 824 #endif 825