1// Copyright 2012 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4// 5// Review notes: 6// 7// - The use of macros in these inline functions may seem superfluous 8// but it is absolutely needed to make sure gcc generates optimal 9// code. gcc is not happy when attempting to inline too deep. 10// 11 12#ifndef V8_OBJECTS_OBJECTS_INL_H_ 13#define V8_OBJECTS_OBJECTS_INL_H_ 14 15#include "src/base/bits.h" 16#include "src/base/memory.h" 17#include "src/base/numbers/double.h" 18#include "src/builtins/builtins.h" 19#include "src/common/globals.h" 20#include "src/common/ptr-compr-inl.h" 21#include "src/handles/handles-inl.h" 22#include "src/heap/factory.h" 23#include "src/heap/heap-write-barrier-inl.h" 24#include "src/heap/read-only-heap-inl.h" 25#include "src/numbers/conversions-inl.h" 26#include "src/objects/bigint.h" 27#include "src/objects/heap-number-inl.h" 28#include "src/objects/heap-object.h" 29#include "src/objects/js-proxy-inl.h" // TODO(jkummerow): Drop. 30#include "src/objects/keys.h" 31#include "src/objects/literal-objects.h" 32#include "src/objects/lookup-inl.h" // TODO(jkummerow): Drop. 33#include "src/objects/objects.h" 34#include "src/objects/oddball-inl.h" 35#include "src/objects/property-details.h" 36#include "src/objects/property.h" 37#include "src/objects/regexp-match-info-inl.h" 38#include "src/objects/shared-function-info.h" 39#include "src/objects/slots-inl.h" 40#include "src/objects/smi-inl.h" 41#include "src/objects/tagged-field-inl.h" 42#include "src/objects/tagged-impl-inl.h" 43#include "src/objects/tagged-index.h" 44#include "src/objects/templates.h" 45#include "src/sandbox/external-pointer-inl.h" 46#include "src/sandbox/sandboxed-pointer-inl.h" 47 48// Has to be the last include (doesn't have include guards): 49#include "src/objects/object-macros.h" 50 51namespace v8 { 52namespace internal { 53 54PropertyDetails::PropertyDetails(Smi smi) { value_ = smi.value(); } 55 56Smi PropertyDetails::AsSmi() const { 57 // Ensure the upper 2 bits have the same value by sign extending it. This is 58 // necessary to be able to use the 31st bit of the property details. 59 int value = value_ << 1; 60 return Smi::FromInt(value >> 1); 61} 62 63int PropertyDetails::field_width_in_words() const { 64 DCHECK_EQ(location(), PropertyLocation::kField); 65 return 1; 66} 67 68DEF_GETTER(HeapObject, IsClassBoilerplate, bool) { 69 return IsFixedArrayExact(cage_base); 70} 71 72bool Object::IsTaggedIndex() const { 73 return IsSmi() && TaggedIndex::IsValid(TaggedIndex(ptr()).value()); 74} 75 76bool Object::InSharedHeap() const { 77 return IsHeapObject() && HeapObject::cast(*this).InSharedHeap(); 78} 79 80bool Object::InSharedWritableHeap() const { 81 return IsHeapObject() && HeapObject::cast(*this).InSharedWritableHeap(); 82} 83 84#define IS_TYPE_FUNCTION_DEF(type_) \ 85 bool Object::Is##type_() const { \ 86 return IsHeapObject() && HeapObject::cast(*this).Is##type_(); \ 87 } \ 88 bool Object::Is##type_(PtrComprCageBase cage_base) const { \ 89 return IsHeapObject() && HeapObject::cast(*this).Is##type_(cage_base); \ 90 } 91HEAP_OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DEF) 92IS_TYPE_FUNCTION_DEF(HashTableBase) 93IS_TYPE_FUNCTION_DEF(SmallOrderedHashTable) 94IS_TYPE_FUNCTION_DEF(CodeT) 95#undef IS_TYPE_FUNCTION_DEF 96 97#define IS_TYPE_FUNCTION_DEF(Type, Value) \ 98 bool Object::Is##Type(Isolate* isolate) const { \ 99 return Is##Type(ReadOnlyRoots(isolate)); \ 100 } \ 101 bool Object::Is##Type(LocalIsolate* isolate) const { \ 102 return Is##Type(ReadOnlyRoots(isolate)); \ 103 } \ 104 bool Object::Is##Type(ReadOnlyRoots roots) const { \ 105 return *this == roots.Value(); \ 106 } \ 107 bool Object::Is##Type() const { \ 108 return IsHeapObject() && HeapObject::cast(*this).Is##Type(); \ 109 } \ 110 bool HeapObject::Is##Type(Isolate* isolate) const { \ 111 return Object::Is##Type(isolate); \ 112 } \ 113 bool HeapObject::Is##Type(LocalIsolate* isolate) const { \ 114 return Object::Is##Type(isolate); \ 115 } \ 116 bool HeapObject::Is##Type(ReadOnlyRoots roots) const { \ 117 return Object::Is##Type(roots); \ 118 } \ 119 bool HeapObject::Is##Type() const { return Is##Type(GetReadOnlyRoots()); } 120ODDBALL_LIST(IS_TYPE_FUNCTION_DEF) 121#undef IS_TYPE_FUNCTION_DEF 122 123bool Object::IsNullOrUndefined(Isolate* isolate) const { 124 return IsNullOrUndefined(ReadOnlyRoots(isolate)); 125} 126 127bool Object::IsNullOrUndefined(ReadOnlyRoots roots) const { 128 return IsNull(roots) || IsUndefined(roots); 129} 130 131bool Object::IsNullOrUndefined() const { 132 return IsHeapObject() && HeapObject::cast(*this).IsNullOrUndefined(); 133} 134 135bool Object::IsZero() const { return *this == Smi::zero(); } 136 137bool Object::IsPublicSymbol() const { 138 return IsSymbol() && !Symbol::cast(*this).is_private(); 139} 140bool Object::IsPrivateSymbol() const { 141 return IsSymbol() && Symbol::cast(*this).is_private(); 142} 143 144bool Object::IsNoSharedNameSentinel() const { 145 return *this == SharedFunctionInfo::kNoSharedNameSentinel; 146} 147 148template <class T, 149 typename std::enable_if<(std::is_arithmetic<T>::value || 150 std::is_enum<T>::value) && 151 !std::is_floating_point<T>::value, 152 int>::type> 153T Object::Relaxed_ReadField(size_t offset) const { 154 // Pointer compression causes types larger than kTaggedSize to be 155 // unaligned. Atomic loads must be aligned. 156 DCHECK_IMPLIES(COMPRESS_POINTERS_BOOL, sizeof(T) <= kTaggedSize); 157 using AtomicT = typename base::AtomicTypeFromByteWidth<sizeof(T)>::type; 158 return static_cast<T>(base::AsAtomicImpl<AtomicT>::Relaxed_Load( 159 reinterpret_cast<AtomicT*>(field_address(offset)))); 160} 161 162template <class T, 163 typename std::enable_if<(std::is_arithmetic<T>::value || 164 std::is_enum<T>::value) && 165 !std::is_floating_point<T>::value, 166 int>::type> 167void Object::Relaxed_WriteField(size_t offset, T value) { 168 // Pointer compression causes types larger than kTaggedSize to be 169 // unaligned. Atomic stores must be aligned. 170 DCHECK_IMPLIES(COMPRESS_POINTERS_BOOL, sizeof(T) <= kTaggedSize); 171 using AtomicT = typename base::AtomicTypeFromByteWidth<sizeof(T)>::type; 172 base::AsAtomicImpl<AtomicT>::Relaxed_Store( 173 reinterpret_cast<AtomicT*>(field_address(offset)), 174 static_cast<AtomicT>(value)); 175} 176 177bool HeapObject::InSharedHeap() const { 178 if (IsReadOnlyHeapObject(*this)) return V8_SHARED_RO_HEAP_BOOL; 179 return InSharedWritableHeap(); 180} 181 182bool HeapObject::InSharedWritableHeap() const { 183 return BasicMemoryChunk::FromHeapObject(*this)->InSharedHeap(); 184} 185 186bool HeapObject::IsNullOrUndefined(Isolate* isolate) const { 187 return IsNullOrUndefined(ReadOnlyRoots(isolate)); 188} 189 190bool HeapObject::IsNullOrUndefined(ReadOnlyRoots roots) const { 191 return Object::IsNullOrUndefined(roots); 192} 193 194bool HeapObject::IsNullOrUndefined() const { 195 return IsNullOrUndefined(GetReadOnlyRoots()); 196} 197 198DEF_GETTER(HeapObject, IsCodeT, bool) { 199 return V8_EXTERNAL_CODE_SPACE_BOOL ? IsCodeDataContainer(cage_base) 200 : IsCode(cage_base); 201} 202 203DEF_GETTER(HeapObject, IsUniqueName, bool) { 204 return IsInternalizedString(cage_base) || IsSymbol(cage_base); 205} 206 207DEF_GETTER(HeapObject, IsFunction, bool) { 208 return IsJSFunctionOrBoundFunctionOrWrappedFunction(); 209} 210 211DEF_GETTER(HeapObject, IsCallable, bool) { 212 return map(cage_base).is_callable(); 213} 214 215DEF_GETTER(HeapObject, IsCallableJSProxy, bool) { 216 return IsCallable(cage_base) && IsJSProxy(cage_base); 217} 218 219DEF_GETTER(HeapObject, IsCallableApiObject, bool) { 220 InstanceType type = map(cage_base).instance_type(); 221 return IsCallable(cage_base) && 222 (type == JS_API_OBJECT_TYPE || type == JS_SPECIAL_API_OBJECT_TYPE); 223} 224 225DEF_GETTER(HeapObject, IsNonNullForeign, bool) { 226 return IsForeign(cage_base) && 227 Foreign::cast(*this).foreign_address() != kNullAddress; 228} 229 230DEF_GETTER(HeapObject, IsConstructor, bool) { 231 return map(cage_base).is_constructor(); 232} 233 234DEF_GETTER(HeapObject, IsSourceTextModuleInfo, bool) { 235 return map(cage_base) == GetReadOnlyRoots(cage_base).module_info_map(); 236} 237 238DEF_GETTER(HeapObject, IsConsString, bool) { 239 if (!IsString(cage_base)) return false; 240 return StringShape(String::cast(*this).map(cage_base)).IsCons(); 241} 242 243DEF_GETTER(HeapObject, IsThinString, bool) { 244 if (!IsString(cage_base)) return false; 245 return StringShape(String::cast(*this).map(cage_base)).IsThin(); 246} 247 248DEF_GETTER(HeapObject, IsSlicedString, bool) { 249 if (!IsString(cage_base)) return false; 250 return StringShape(String::cast(*this).map(cage_base)).IsSliced(); 251} 252 253DEF_GETTER(HeapObject, IsSeqString, bool) { 254 if (!IsString(cage_base)) return false; 255 return StringShape(String::cast(*this).map(cage_base)).IsSequential(); 256} 257 258DEF_GETTER(HeapObject, IsSeqOneByteString, bool) { 259 if (!IsString(cage_base)) return false; 260 return StringShape(String::cast(*this).map(cage_base)).IsSequential() && 261 String::cast(*this).IsOneByteRepresentation(cage_base); 262} 263 264DEF_GETTER(HeapObject, IsSeqTwoByteString, bool) { 265 if (!IsString(cage_base)) return false; 266 return StringShape(String::cast(*this).map(cage_base)).IsSequential() && 267 String::cast(*this).IsTwoByteRepresentation(cage_base); 268} 269 270DEF_GETTER(HeapObject, IsExternalOneByteString, bool) { 271 if (!IsString(cage_base)) return false; 272 return StringShape(String::cast(*this).map(cage_base)).IsExternal() && 273 String::cast(*this).IsOneByteRepresentation(cage_base); 274} 275 276DEF_GETTER(HeapObject, IsExternalTwoByteString, bool) { 277 if (!IsString(cage_base)) return false; 278 return StringShape(String::cast(*this).map(cage_base)).IsExternal() && 279 String::cast(*this).IsTwoByteRepresentation(cage_base); 280} 281 282bool Object::IsNumber() const { 283 if (IsSmi()) return true; 284 HeapObject this_heap_object = HeapObject::cast(*this); 285 PtrComprCageBase cage_base = GetPtrComprCageBase(this_heap_object); 286 return this_heap_object.IsHeapNumber(cage_base); 287} 288 289bool Object::IsNumber(PtrComprCageBase cage_base) const { 290 return IsSmi() || IsHeapNumber(cage_base); 291} 292 293bool Object::IsNumeric() const { 294 if (IsSmi()) return true; 295 HeapObject this_heap_object = HeapObject::cast(*this); 296 PtrComprCageBase cage_base = GetPtrComprCageBase(this_heap_object); 297 return this_heap_object.IsHeapNumber(cage_base) || 298 this_heap_object.IsBigInt(cage_base); 299} 300 301bool Object::IsNumeric(PtrComprCageBase cage_base) const { 302 return IsNumber(cage_base) || IsBigInt(cage_base); 303} 304 305DEF_GETTER(HeapObject, IsArrayList, bool) { 306 return map(cage_base) == 307 GetReadOnlyRoots(cage_base).unchecked_array_list_map(); 308} 309 310DEF_GETTER(HeapObject, IsRegExpMatchInfo, bool) { 311 return IsFixedArrayExact(cage_base); 312} 313 314DEF_GETTER(HeapObject, IsDeoptimizationData, bool) { 315 // Must be a fixed array. 316 if (!IsFixedArrayExact(cage_base)) return false; 317 318 // There's no sure way to detect the difference between a fixed array and 319 // a deoptimization data array. Since this is used for asserts we can 320 // check that the length is zero or else the fixed size plus a multiple of 321 // the entry size. 322 int length = FixedArray::cast(*this).length(); 323 if (length == 0) return true; 324 325 length -= DeoptimizationData::kFirstDeoptEntryIndex; 326 return length >= 0 && length % DeoptimizationData::kDeoptEntrySize == 0; 327} 328 329DEF_GETTER(HeapObject, IsHandlerTable, bool) { 330 return IsFixedArrayExact(cage_base); 331} 332 333DEF_GETTER(HeapObject, IsTemplateList, bool) { 334 if (!IsFixedArrayExact(cage_base)) return false; 335 if (FixedArray::cast(*this).length() < 1) return false; 336 return true; 337} 338 339DEF_GETTER(HeapObject, IsDependentCode, bool) { 340 return IsWeakArrayList(cage_base); 341} 342 343DEF_GETTER(HeapObject, IsOSROptimizedCodeCache, bool) { 344 return IsWeakFixedArray(cage_base); 345} 346 347bool HeapObject::IsAbstractCode() const { 348 // TODO(v8:11880): Either make AbstractCode be ByteArray|CodeT or 349 // ensure this version is not called for hot code. 350 PtrComprCageBase cage_base = GetPtrComprCageBaseSlow(*this); 351 return HeapObject::IsAbstractCode(cage_base); 352} 353bool HeapObject::IsAbstractCode(PtrComprCageBase cage_base) const { 354 return IsBytecodeArray(cage_base) || IsCode(cage_base); 355} 356 357DEF_GETTER(HeapObject, IsStringWrapper, bool) { 358 return IsJSPrimitiveWrapper(cage_base) && 359 JSPrimitiveWrapper::cast(*this).value().IsString(cage_base); 360} 361 362DEF_GETTER(HeapObject, IsBooleanWrapper, bool) { 363 return IsJSPrimitiveWrapper(cage_base) && 364 JSPrimitiveWrapper::cast(*this).value().IsBoolean(cage_base); 365} 366 367DEF_GETTER(HeapObject, IsScriptWrapper, bool) { 368 return IsJSPrimitiveWrapper(cage_base) && 369 JSPrimitiveWrapper::cast(*this).value().IsScript(cage_base); 370} 371 372DEF_GETTER(HeapObject, IsNumberWrapper, bool) { 373 return IsJSPrimitiveWrapper(cage_base) && 374 JSPrimitiveWrapper::cast(*this).value().IsNumber(cage_base); 375} 376 377DEF_GETTER(HeapObject, IsBigIntWrapper, bool) { 378 return IsJSPrimitiveWrapper(cage_base) && 379 JSPrimitiveWrapper::cast(*this).value().IsBigInt(cage_base); 380} 381 382DEF_GETTER(HeapObject, IsSymbolWrapper, bool) { 383 return IsJSPrimitiveWrapper(cage_base) && 384 JSPrimitiveWrapper::cast(*this).value().IsSymbol(cage_base); 385} 386 387DEF_GETTER(HeapObject, IsStringSet, bool) { return IsHashTable(cage_base); } 388 389DEF_GETTER(HeapObject, IsObjectHashSet, bool) { return IsHashTable(cage_base); } 390 391DEF_GETTER(HeapObject, IsCompilationCacheTable, bool) { 392 return IsHashTable(cage_base); 393} 394 395DEF_GETTER(HeapObject, IsMapCache, bool) { return IsHashTable(cage_base); } 396 397DEF_GETTER(HeapObject, IsObjectHashTable, bool) { 398 return IsHashTable(cage_base); 399} 400 401DEF_GETTER(HeapObject, IsHashTableBase, bool) { return IsHashTable(cage_base); } 402 403#if V8_ENABLE_WEBASSEMBLY 404DEF_GETTER(HeapObject, IsWasmExceptionPackage, bool) { 405 // It is not possible to check for the existence of certain properties on the 406 // underlying {JSReceiver} here because that requires calling handlified code. 407 return IsJSReceiver(cage_base); 408} 409#endif // V8_ENABLE_WEBASSEMBLY 410 411bool Object::IsPrimitive() const { 412 if (IsSmi()) return true; 413 HeapObject this_heap_object = HeapObject::cast(*this); 414 PtrComprCageBase cage_base = GetPtrComprCageBase(this_heap_object); 415 return this_heap_object.map(cage_base).IsPrimitiveMap(); 416} 417 418bool Object::IsPrimitive(PtrComprCageBase cage_base) const { 419 return IsSmi() || HeapObject::cast(*this).map(cage_base).IsPrimitiveMap(); 420} 421 422// static 423Maybe<bool> Object::IsArray(Handle<Object> object) { 424 if (object->IsSmi()) return Just(false); 425 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); 426 if (heap_object->IsJSArray()) return Just(true); 427 if (!heap_object->IsJSProxy()) return Just(false); 428 return JSProxy::IsArray(Handle<JSProxy>::cast(object)); 429} 430 431DEF_GETTER(HeapObject, IsUndetectable, bool) { 432 return map(cage_base).is_undetectable(); 433} 434 435DEF_GETTER(HeapObject, IsAccessCheckNeeded, bool) { 436 if (IsJSGlobalProxy(cage_base)) { 437 const JSGlobalProxy proxy = JSGlobalProxy::cast(*this); 438 JSGlobalObject global = proxy.GetIsolate()->context().global_object(); 439 return proxy.IsDetachedFrom(global); 440 } 441 return map(cage_base).is_access_check_needed(); 442} 443 444#define MAKE_STRUCT_PREDICATE(NAME, Name, name) \ 445 bool Object::Is##Name() const { \ 446 return IsHeapObject() && HeapObject::cast(*this).Is##Name(); \ 447 } \ 448 bool Object::Is##Name(PtrComprCageBase cage_base) const { \ 449 return IsHeapObject() && HeapObject::cast(*this).Is##Name(cage_base); \ 450 } 451STRUCT_LIST(MAKE_STRUCT_PREDICATE) 452#undef MAKE_STRUCT_PREDICATE 453 454double Object::Number() const { 455 DCHECK(IsNumber()); 456 return IsSmi() ? static_cast<double>(Smi(this->ptr()).value()) 457 : HeapNumber::unchecked_cast(*this).value(); 458} 459 460// static 461bool Object::SameNumberValue(double value1, double value2) { 462 // SameNumberValue(NaN, NaN) is true. 463 if (value1 != value2) { 464 return std::isnan(value1) && std::isnan(value2); 465 } 466 // SameNumberValue(0.0, -0.0) is false. 467 return (std::signbit(value1) == std::signbit(value2)); 468} 469 470bool Object::IsNaN() const { 471 return this->IsHeapNumber() && std::isnan(HeapNumber::cast(*this).value()); 472} 473 474bool Object::IsMinusZero() const { 475 return this->IsHeapNumber() && 476 i::IsMinusZero(HeapNumber::cast(*this).value()); 477} 478 479OBJECT_CONSTRUCTORS_IMPL(BigIntBase, PrimitiveHeapObject) 480OBJECT_CONSTRUCTORS_IMPL(BigInt, BigIntBase) 481OBJECT_CONSTRUCTORS_IMPL(FreshlyAllocatedBigInt, BigIntBase) 482 483// ------------------------------------ 484// Cast operations 485 486CAST_ACCESSOR(BigIntBase) 487CAST_ACCESSOR(BigInt) 488 489bool Object::HasValidElements() { 490 // Dictionary is covered under FixedArray. ByteArray is used 491 // for the JSTypedArray backing stores. 492 return IsFixedArray() || IsFixedDoubleArray() || IsByteArray(); 493} 494 495bool Object::FilterKey(PropertyFilter filter) { 496 DCHECK(!IsPropertyCell()); 497 if (filter == PRIVATE_NAMES_ONLY) { 498 if (!IsSymbol()) return true; 499 return !Symbol::cast(*this).is_private_name(); 500 } else if (IsSymbol()) { 501 if (filter & SKIP_SYMBOLS) return true; 502 503 if (Symbol::cast(*this).is_private()) return true; 504 } else { 505 if (filter & SKIP_STRINGS) return true; 506 } 507 return false; 508} 509 510Representation Object::OptimalRepresentation(PtrComprCageBase cage_base) const { 511 if (IsSmi()) { 512 return Representation::Smi(); 513 } 514 HeapObject heap_object = HeapObject::cast(*this); 515 if (heap_object.IsHeapNumber(cage_base)) { 516 return Representation::Double(); 517 } else if (heap_object.IsUninitialized( 518 heap_object.GetReadOnlyRoots(cage_base))) { 519 return Representation::None(); 520 } 521 return Representation::HeapObject(); 522} 523 524ElementsKind Object::OptimalElementsKind(PtrComprCageBase cage_base) const { 525 if (IsSmi()) return PACKED_SMI_ELEMENTS; 526 if (IsNumber(cage_base)) return PACKED_DOUBLE_ELEMENTS; 527 return PACKED_ELEMENTS; 528} 529 530bool Object::FitsRepresentation(Representation representation, 531 bool allow_coercion) const { 532 if (representation.IsSmi()) { 533 return IsSmi(); 534 } else if (representation.IsDouble()) { 535 return allow_coercion ? IsNumber() : IsHeapNumber(); 536 } else if (representation.IsHeapObject()) { 537 return IsHeapObject(); 538 } else if (representation.IsNone()) { 539 return false; 540 } 541 return true; 542} 543 544bool Object::ToUint32(uint32_t* value) const { 545 if (IsSmi()) { 546 int num = Smi::ToInt(*this); 547 if (num < 0) return false; 548 *value = static_cast<uint32_t>(num); 549 return true; 550 } 551 if (IsHeapNumber()) { 552 double num = HeapNumber::cast(*this).value(); 553 return DoubleToUint32IfEqualToSelf(num, value); 554 } 555 return false; 556} 557 558// static 559MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate, 560 Handle<Object> object, 561 const char* method_name) { 562 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); 563 return ToObjectImpl(isolate, object, method_name); 564} 565 566// static 567MaybeHandle<Name> Object::ToName(Isolate* isolate, Handle<Object> input) { 568 if (input->IsName()) return Handle<Name>::cast(input); 569 return ConvertToName(isolate, input); 570} 571 572// static 573MaybeHandle<Object> Object::ToPropertyKey(Isolate* isolate, 574 Handle<Object> value) { 575 if (value->IsSmi() || HeapObject::cast(*value).IsName()) return value; 576 return ConvertToPropertyKey(isolate, value); 577} 578 579// static 580MaybeHandle<Object> Object::ToPrimitive(Isolate* isolate, Handle<Object> input, 581 ToPrimitiveHint hint) { 582 if (input->IsPrimitive()) return input; 583 return JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(input), 584 hint); 585} 586 587// static 588MaybeHandle<Object> Object::ToNumber(Isolate* isolate, Handle<Object> input) { 589 if (input->IsNumber()) return input; // Shortcut. 590 return ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber); 591} 592 593// static 594MaybeHandle<Object> Object::ToNumeric(Isolate* isolate, Handle<Object> input) { 595 if (input->IsNumber() || input->IsBigInt()) return input; // Shortcut. 596 return ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumeric); 597} 598 599// static 600MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) { 601 if (input->IsSmi()) return input; 602 return ConvertToInteger(isolate, input); 603} 604 605// static 606MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) { 607 if (input->IsSmi()) return input; 608 return ConvertToInt32(isolate, input); 609} 610 611// static 612MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) { 613 if (input->IsSmi()) return handle(Smi::cast(*input).ToUint32Smi(), isolate); 614 return ConvertToUint32(isolate, input); 615} 616 617// static 618MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) { 619 if (input->IsString()) return Handle<String>::cast(input); 620 return ConvertToString(isolate, input); 621} 622 623// static 624MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) { 625 if (input->IsSmi()) { 626 int value = std::max(Smi::ToInt(*input), 0); 627 return handle(Smi::FromInt(value), isolate); 628 } 629 return ConvertToLength(isolate, input); 630} 631 632// static 633MaybeHandle<Object> Object::ToIndex(Isolate* isolate, Handle<Object> input, 634 MessageTemplate error_index) { 635 if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input; 636 return ConvertToIndex(isolate, input, error_index); 637} 638 639MaybeHandle<Object> Object::GetProperty(Isolate* isolate, Handle<Object> object, 640 Handle<Name> name) { 641 LookupIterator it(isolate, object, name); 642 if (!it.IsFound()) return it.factory()->undefined_value(); 643 return GetProperty(&it); 644} 645 646MaybeHandle<Object> Object::GetElement(Isolate* isolate, Handle<Object> object, 647 uint32_t index) { 648 LookupIterator it(isolate, object, index); 649 if (!it.IsFound()) return it.factory()->undefined_value(); 650 return GetProperty(&it); 651} 652 653MaybeHandle<Object> Object::SetElement(Isolate* isolate, Handle<Object> object, 654 uint32_t index, Handle<Object> value, 655 ShouldThrow should_throw) { 656 LookupIterator it(isolate, object, index); 657 MAYBE_RETURN_NULL( 658 SetProperty(&it, value, StoreOrigin::kMaybeKeyed, Just(should_throw))); 659 return value; 660} 661 662Address Object::ReadSandboxedPointerField(size_t offset, 663 PtrComprCageBase cage_base) const { 664 return i::ReadSandboxedPointerField(field_address(offset), cage_base); 665} 666 667void Object::WriteSandboxedPointerField(size_t offset, 668 PtrComprCageBase cage_base, 669 Address value) { 670 i::WriteSandboxedPointerField(field_address(offset), cage_base, value); 671} 672 673void Object::WriteSandboxedPointerField(size_t offset, Isolate* isolate, 674 Address value) { 675 i::WriteSandboxedPointerField(field_address(offset), 676 PtrComprCageBase(isolate), value); 677} 678 679void Object::InitExternalPointerField(size_t offset, Isolate* isolate, 680 ExternalPointerTag tag) { 681 i::InitExternalPointerField(field_address(offset), isolate, tag); 682} 683 684void Object::InitExternalPointerField(size_t offset, Isolate* isolate, 685 Address value, ExternalPointerTag tag) { 686 i::InitExternalPointerField(field_address(offset), isolate, value, tag); 687} 688 689Address Object::ReadExternalPointerField(size_t offset, Isolate* isolate, 690 ExternalPointerTag tag) const { 691 return i::ReadExternalPointerField(field_address(offset), isolate, tag); 692} 693 694void Object::WriteExternalPointerField(size_t offset, Isolate* isolate, 695 Address value, ExternalPointerTag tag) { 696 i::WriteExternalPointerField(field_address(offset), isolate, value, tag); 697} 698 699ObjectSlot HeapObject::RawField(int byte_offset) const { 700 return ObjectSlot(field_address(byte_offset)); 701} 702 703MaybeObjectSlot HeapObject::RawMaybeWeakField(int byte_offset) const { 704 return MaybeObjectSlot(field_address(byte_offset)); 705} 706 707CodeObjectSlot HeapObject::RawCodeField(int byte_offset) const { 708 return CodeObjectSlot(field_address(byte_offset)); 709} 710 711ExternalPointer_t HeapObject::RawExternalPointerField(int byte_offset) const { 712 return ReadRawExternalPointerField(field_address(byte_offset)); 713} 714 715MapWord MapWord::FromMap(const Map map) { 716 DCHECK(map.is_null() || !MapWord::IsPacked(map.ptr())); 717#ifdef V8_MAP_PACKING 718 return MapWord(Pack(map.ptr())); 719#else 720 return MapWord(map.ptr()); 721#endif 722} 723 724Map MapWord::ToMap() const { 725#ifdef V8_MAP_PACKING 726 return Map::unchecked_cast(Object(Unpack(value_))); 727#else 728 return Map::unchecked_cast(Object(value_)); 729#endif 730} 731 732bool MapWord::IsForwardingAddress() const { 733 return (value_ & kForwardingTagMask) == kForwardingTag; 734} 735 736MapWord MapWord::FromForwardingAddress(HeapObject object) { 737 return MapWord(object.ptr() - kHeapObjectTag); 738} 739 740HeapObject MapWord::ToForwardingAddress() { 741 DCHECK(IsForwardingAddress()); 742 HeapObject obj = HeapObject::FromAddress(value_); 743 // For objects allocated outside of the main pointer compression cage the 744 // variant with explicit cage base must be used. 745 DCHECK_IMPLIES(V8_EXTERNAL_CODE_SPACE_BOOL, !IsCodeSpaceObject(obj)); 746 return obj; 747} 748 749HeapObject MapWord::ToForwardingAddress(PtrComprCageBase host_cage_base) { 750 DCHECK(IsForwardingAddress()); 751 if (V8_EXTERNAL_CODE_SPACE_BOOL) { 752 // Recompress value_ using proper host_cage_base since the map word 753 // has the upper 32 bits that correspond to the main cage base value. 754 Address value = 755 DecompressTaggedPointer(host_cage_base, CompressTagged(value_)); 756 return HeapObject::FromAddress(value); 757 } 758 return HeapObject::FromAddress(value_); 759} 760 761#ifdef VERIFY_HEAP 762void HeapObject::VerifyObjectField(Isolate* isolate, int offset) { 763 VerifyPointer(isolate, TaggedField<Object>::load(isolate, *this, offset)); 764 STATIC_ASSERT(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size); 765} 766 767void HeapObject::VerifyMaybeObjectField(Isolate* isolate, int offset) { 768 MaybeObject::VerifyMaybeObjectPointer( 769 isolate, TaggedField<MaybeObject>::load(isolate, *this, offset)); 770 STATIC_ASSERT(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size); 771} 772 773void HeapObject::VerifySmiField(int offset) { 774 CHECK(TaggedField<Object>::load(*this, offset).IsSmi()); 775 STATIC_ASSERT(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size); 776} 777 778#endif 779 780ReadOnlyRoots HeapObject::GetReadOnlyRoots() const { 781 return ReadOnlyHeap::GetReadOnlyRoots(*this); 782} 783 784ReadOnlyRoots HeapObject::GetReadOnlyRoots(PtrComprCageBase cage_base) const { 785#ifdef V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE 786 DCHECK_NE(cage_base.address(), 0); 787 return ReadOnlyRoots(Isolate::FromRootAddress(cage_base.address())); 788#else 789 return GetReadOnlyRoots(); 790#endif 791} 792 793Map HeapObject::map() const { 794 // This method is never used for objects located in code space (Code and 795 // free space fillers) and thus it is fine to use auto-computed cage base 796 // value. 797 DCHECK_IMPLIES(V8_EXTERNAL_CODE_SPACE_BOOL, !IsCodeSpaceObject(*this)); 798 PtrComprCageBase cage_base = GetPtrComprCageBase(*this); 799 return HeapObject::map(cage_base); 800} 801Map HeapObject::map(PtrComprCageBase cage_base) const { 802 return map_word(cage_base, kRelaxedLoad).ToMap(); 803} 804 805void HeapObject::set_map(Map value) { 806 set_map<EmitWriteBarrier::kYes>(value, kRelaxedStore, 807 VerificationMode::kPotentialLayoutChange); 808} 809 810void HeapObject::set_map(Map value, ReleaseStoreTag tag) { 811 set_map<EmitWriteBarrier::kYes>(value, kReleaseStore, 812 VerificationMode::kPotentialLayoutChange); 813} 814 815void HeapObject::set_map_safe_transition(Map value) { 816 set_map<EmitWriteBarrier::kYes>(value, kRelaxedStore, 817 VerificationMode::kSafeMapTransition); 818} 819 820void HeapObject::set_map_safe_transition(Map value, ReleaseStoreTag tag) { 821 set_map<EmitWriteBarrier::kYes>(value, kReleaseStore, 822 VerificationMode::kSafeMapTransition); 823} 824 825// Unsafe accessor omitting write barrier. 826void HeapObject::set_map_no_write_barrier(Map value, RelaxedStoreTag tag) { 827 set_map<EmitWriteBarrier::kNo>(value, kRelaxedStore, 828 VerificationMode::kPotentialLayoutChange); 829} 830 831void HeapObject::set_map_no_write_barrier(Map value, ReleaseStoreTag tag) { 832 set_map<EmitWriteBarrier::kNo>(value, kReleaseStore, 833 VerificationMode::kPotentialLayoutChange); 834} 835 836template <HeapObject::EmitWriteBarrier emit_write_barrier, typename MemoryOrder> 837void HeapObject::set_map(Map value, MemoryOrder order, VerificationMode mode) { 838#if V8_ENABLE_WEBASSEMBLY 839 // In {WasmGraphBuilder::SetMap} and {WasmGraphBuilder::LoadMap}, we treat 840 // maps as immutable. Therefore we are not allowed to mutate them here. 841 DCHECK(!value.IsWasmStructMap() && !value.IsWasmArrayMap()); 842#endif 843 // Object layout changes are currently not supported on background threads. 844 // This method might change object layout and therefore can't be used on 845 // background threads. 846 DCHECK_IMPLIES(mode != VerificationMode::kSafeMapTransition, 847 !LocalHeap::Current()); 848#ifdef VERIFY_HEAP 849 if (FLAG_verify_heap && !value.is_null()) { 850 Heap* heap = GetHeapFromWritableObject(*this); 851 if (mode == VerificationMode::kSafeMapTransition) { 852 heap->VerifySafeMapTransition(*this, value); 853 } else { 854 DCHECK_EQ(mode, VerificationMode::kPotentialLayoutChange); 855 heap->VerifyObjectLayoutChange(*this, value); 856 } 857 } 858#endif 859 set_map_word(MapWord::FromMap(value), order); 860#ifndef V8_DISABLE_WRITE_BARRIERS 861 if (!value.is_null()) { 862 if (emit_write_barrier == EmitWriteBarrier::kYes) { 863 WriteBarrier::Marking(*this, map_slot(), value); 864 } else { 865 DCHECK_EQ(emit_write_barrier, EmitWriteBarrier::kNo); 866 SLOW_DCHECK(!WriteBarrier::IsRequired(*this, value)); 867 } 868 } 869#endif 870} 871 872void HeapObject::set_map_after_allocation(Map value, WriteBarrierMode mode) { 873 MapWord mapword = MapWord::FromMap(value); 874 set_map_word(mapword, kRelaxedStore); 875#ifndef V8_DISABLE_WRITE_BARRIERS 876 if (mode != SKIP_WRITE_BARRIER) { 877 DCHECK(!value.is_null()); 878 WriteBarrier::Marking(*this, map_slot(), value); 879 } else { 880 SLOW_DCHECK(!WriteBarrier::IsRequired(*this, value)); 881 } 882#endif 883} 884 885DEF_ACQUIRE_GETTER(HeapObject, map, Map) { 886 return map_word(cage_base, kAcquireLoad).ToMap(); 887} 888 889ObjectSlot HeapObject::map_slot() const { 890 return ObjectSlot(MapField::address(*this)); 891} 892 893MapWord HeapObject::map_word(RelaxedLoadTag tag) const { 894 // This method is never used for objects located in code space (Code and 895 // free space fillers) and thus it is fine to use auto-computed cage base 896 // value. 897 DCHECK_IMPLIES(V8_EXTERNAL_CODE_SPACE_BOOL, !IsCodeSpaceObject(*this)); 898 PtrComprCageBase cage_base = GetPtrComprCageBase(*this); 899 return HeapObject::map_word(cage_base, tag); 900} 901MapWord HeapObject::map_word(PtrComprCageBase cage_base, 902 RelaxedLoadTag tag) const { 903 return MapField::Relaxed_Load_Map_Word(cage_base, *this); 904} 905 906void HeapObject::set_map_word(MapWord map_word, RelaxedStoreTag) { 907 MapField::Relaxed_Store_Map_Word(*this, map_word); 908} 909 910MapWord HeapObject::map_word(AcquireLoadTag tag) const { 911 // This method is never used for objects located in code space (Code and 912 // free space fillers) and thus it is fine to use auto-computed cage base 913 // value. 914 DCHECK_IMPLIES(V8_EXTERNAL_CODE_SPACE_BOOL, !IsCodeSpaceObject(*this)); 915 PtrComprCageBase cage_base = GetPtrComprCageBase(*this); 916 return HeapObject::map_word(cage_base, tag); 917} 918MapWord HeapObject::map_word(PtrComprCageBase cage_base, 919 AcquireLoadTag tag) const { 920 return MapField::Acquire_Load_No_Unpack(cage_base, *this); 921} 922 923void HeapObject::set_map_word(MapWord map_word, ReleaseStoreTag) { 924 MapField::Release_Store_Map_Word(*this, map_word); 925} 926 927bool HeapObject::release_compare_and_swap_map_word(MapWord old_map_word, 928 MapWord new_map_word) { 929 Tagged_t result = 930 MapField::Release_CompareAndSwap(*this, old_map_word, new_map_word); 931 return result == static_cast<Tagged_t>(old_map_word.ptr()); 932} 933 934// TODO(v8:11880): consider dropping parameterless version. 935int HeapObject::Size() const { 936 DCHECK_IMPLIES(V8_EXTERNAL_CODE_SPACE_BOOL, !IsCodeSpaceObject(*this)); 937 PtrComprCageBase cage_base = GetPtrComprCageBase(*this); 938 return HeapObject::Size(cage_base); 939} 940int HeapObject::Size(PtrComprCageBase cage_base) const { 941 return SizeFromMap(map(cage_base)); 942} 943 944inline bool IsSpecialReceiverInstanceType(InstanceType instance_type) { 945 return instance_type <= LAST_SPECIAL_RECEIVER_TYPE; 946} 947 948// This should be in objects/map-inl.h, but can't, because of a cyclic 949// dependency. 950bool Map::IsSpecialReceiverMap() const { 951 bool result = IsSpecialReceiverInstanceType(instance_type()); 952 DCHECK_IMPLIES(!result, 953 !has_named_interceptor() && !is_access_check_needed()); 954 return result; 955} 956 957inline bool IsCustomElementsReceiverInstanceType(InstanceType instance_type) { 958 return instance_type <= LAST_CUSTOM_ELEMENTS_RECEIVER; 959} 960 961// This should be in objects/map-inl.h, but can't, because of a cyclic 962// dependency. 963bool Map::IsCustomElementsReceiverMap() const { 964 return IsCustomElementsReceiverInstanceType(instance_type()); 965} 966 967bool Object::ToArrayLength(uint32_t* index) const { 968 return Object::ToUint32(index); 969} 970 971bool Object::ToArrayIndex(uint32_t* index) const { 972 return Object::ToUint32(index) && *index != kMaxUInt32; 973} 974 975bool Object::ToIntegerIndex(size_t* index) const { 976 if (IsSmi()) { 977 int num = Smi::ToInt(*this); 978 if (num < 0) return false; 979 *index = static_cast<size_t>(num); 980 return true; 981 } 982 if (IsHeapNumber()) { 983 double num = HeapNumber::cast(*this).value(); 984 if (!(num >= 0)) return false; // Negation to catch NaNs. 985 constexpr double max = 986 std::min(kMaxSafeInteger, 987 // The maximum size_t is reserved as "invalid" sentinel. 988 static_cast<double>(std::numeric_limits<size_t>::max() - 1)); 989 if (num > max) return false; 990 size_t result = static_cast<size_t>(num); 991 if (num != result) return false; // Conversion lost fractional precision. 992 *index = result; 993 return true; 994 } 995 return false; 996} 997 998WriteBarrierMode HeapObject::GetWriteBarrierMode( 999 const DisallowGarbageCollection& promise) { 1000 return GetWriteBarrierModeForObject(*this, &promise); 1001} 1002 1003// static 1004AllocationAlignment HeapObject::RequiredAlignment(Map map) { 1005 // TODO(v8:4153): We should think about requiring double alignment 1006 // in general for ByteArray, since they are used as backing store for typed 1007 // arrays now. 1008 // TODO(ishell, v8:8875): Consider using aligned allocations for BigInt. 1009 if (USE_ALLOCATION_ALIGNMENT_BOOL) { 1010 int instance_type = map.instance_type(); 1011 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) return kDoubleAligned; 1012 if (instance_type == HEAP_NUMBER_TYPE) return kDoubleUnaligned; 1013 } 1014 return kTaggedAligned; 1015} 1016 1017Address HeapObject::GetFieldAddress(int field_offset) const { 1018 return field_address(field_offset); 1019} 1020 1021// static 1022Maybe<bool> Object::GreaterThan(Isolate* isolate, Handle<Object> x, 1023 Handle<Object> y) { 1024 Maybe<ComparisonResult> result = Compare(isolate, x, y); 1025 if (result.IsJust()) { 1026 switch (result.FromJust()) { 1027 case ComparisonResult::kGreaterThan: 1028 return Just(true); 1029 case ComparisonResult::kLessThan: 1030 case ComparisonResult::kEqual: 1031 case ComparisonResult::kUndefined: 1032 return Just(false); 1033 } 1034 } 1035 return Nothing<bool>(); 1036} 1037 1038// static 1039Maybe<bool> Object::GreaterThanOrEqual(Isolate* isolate, Handle<Object> x, 1040 Handle<Object> y) { 1041 Maybe<ComparisonResult> result = Compare(isolate, x, y); 1042 if (result.IsJust()) { 1043 switch (result.FromJust()) { 1044 case ComparisonResult::kEqual: 1045 case ComparisonResult::kGreaterThan: 1046 return Just(true); 1047 case ComparisonResult::kLessThan: 1048 case ComparisonResult::kUndefined: 1049 return Just(false); 1050 } 1051 } 1052 return Nothing<bool>(); 1053} 1054 1055// static 1056Maybe<bool> Object::LessThan(Isolate* isolate, Handle<Object> x, 1057 Handle<Object> y) { 1058 Maybe<ComparisonResult> result = Compare(isolate, x, y); 1059 if (result.IsJust()) { 1060 switch (result.FromJust()) { 1061 case ComparisonResult::kLessThan: 1062 return Just(true); 1063 case ComparisonResult::kEqual: 1064 case ComparisonResult::kGreaterThan: 1065 case ComparisonResult::kUndefined: 1066 return Just(false); 1067 } 1068 } 1069 return Nothing<bool>(); 1070} 1071 1072// static 1073Maybe<bool> Object::LessThanOrEqual(Isolate* isolate, Handle<Object> x, 1074 Handle<Object> y) { 1075 Maybe<ComparisonResult> result = Compare(isolate, x, y); 1076 if (result.IsJust()) { 1077 switch (result.FromJust()) { 1078 case ComparisonResult::kEqual: 1079 case ComparisonResult::kLessThan: 1080 return Just(true); 1081 case ComparisonResult::kGreaterThan: 1082 case ComparisonResult::kUndefined: 1083 return Just(false); 1084 } 1085 } 1086 return Nothing<bool>(); 1087} 1088 1089MaybeHandle<Object> Object::GetPropertyOrElement(Isolate* isolate, 1090 Handle<Object> object, 1091 Handle<Name> name) { 1092 PropertyKey key(isolate, name); 1093 LookupIterator it(isolate, object, key); 1094 return GetProperty(&it); 1095} 1096 1097MaybeHandle<Object> Object::SetPropertyOrElement( 1098 Isolate* isolate, Handle<Object> object, Handle<Name> name, 1099 Handle<Object> value, Maybe<ShouldThrow> should_throw, 1100 StoreOrigin store_origin) { 1101 PropertyKey key(isolate, name); 1102 LookupIterator it(isolate, object, key); 1103 MAYBE_RETURN_NULL(SetProperty(&it, value, store_origin, should_throw)); 1104 return value; 1105} 1106 1107MaybeHandle<Object> Object::GetPropertyOrElement(Handle<Object> receiver, 1108 Handle<Name> name, 1109 Handle<JSReceiver> holder) { 1110 Isolate* isolate = holder->GetIsolate(); 1111 PropertyKey key(isolate, name); 1112 LookupIterator it(isolate, receiver, key, holder); 1113 return GetProperty(&it); 1114} 1115 1116// static 1117Object Object::GetSimpleHash(Object object) { 1118 DisallowGarbageCollection no_gc; 1119 if (object.IsSmi()) { 1120 uint32_t hash = ComputeUnseededHash(Smi::ToInt(object)); 1121 return Smi::FromInt(hash & Smi::kMaxValue); 1122 } 1123 auto instance_type = HeapObject::cast(object).map().instance_type(); 1124 if (InstanceTypeChecker::IsHeapNumber(instance_type)) { 1125 double num = HeapNumber::cast(object).value(); 1126 if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue); 1127 // Use ComputeUnseededHash for all values in Signed32 range, including -0, 1128 // which is considered equal to 0 because collections use SameValueZero. 1129 uint32_t hash; 1130 // Check range before conversion to avoid undefined behavior. 1131 if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) { 1132 hash = ComputeUnseededHash(FastD2I(num)); 1133 } else { 1134 hash = ComputeLongHash(base::double_to_uint64(num)); 1135 } 1136 return Smi::FromInt(hash & Smi::kMaxValue); 1137 } else if (InstanceTypeChecker::IsName(instance_type)) { 1138 uint32_t hash = Name::cast(object).EnsureHash(); 1139 return Smi::FromInt(hash); 1140 } else if (InstanceTypeChecker::IsOddball(instance_type)) { 1141 uint32_t hash = Oddball::cast(object).to_string().EnsureHash(); 1142 return Smi::FromInt(hash); 1143 } else if (InstanceTypeChecker::IsBigInt(instance_type)) { 1144 uint32_t hash = BigInt::cast(object).Hash(); 1145 return Smi::FromInt(hash & Smi::kMaxValue); 1146 } else if (InstanceTypeChecker::IsSharedFunctionInfo(instance_type)) { 1147 uint32_t hash = SharedFunctionInfo::cast(object).Hash(); 1148 return Smi::FromInt(hash & Smi::kMaxValue); 1149 } 1150 DCHECK(object.IsJSReceiver()); 1151 return object; 1152} 1153 1154Object Object::GetHash() { 1155 DisallowGarbageCollection no_gc; 1156 Object hash = GetSimpleHash(*this); 1157 if (hash.IsSmi()) return hash; 1158 1159 DCHECK(IsJSReceiver()); 1160 JSReceiver receiver = JSReceiver::cast(*this); 1161 return receiver.GetIdentityHash(); 1162} 1163 1164bool Object::IsShared() const { 1165 // This logic should be kept in sync with fast paths in 1166 // CodeStubAssembler::SharedValueBarrier. 1167 1168 // Smis are trivially shared. 1169 if (IsSmi()) return true; 1170 1171 HeapObject object = HeapObject::cast(*this); 1172 1173 // RO objects are shared when the RO space is shared. 1174 if (IsReadOnlyHeapObject(object)) { 1175 return ReadOnlyHeap::IsReadOnlySpaceShared(); 1176 } 1177 1178 // Check if this object is already shared. 1179 switch (object.map().instance_type()) { 1180 case SHARED_STRING_TYPE: 1181 case SHARED_ONE_BYTE_STRING_TYPE: 1182 case JS_SHARED_STRUCT_TYPE: 1183 DCHECK(object.InSharedHeap()); 1184 return true; 1185 case INTERNALIZED_STRING_TYPE: 1186 case ONE_BYTE_INTERNALIZED_STRING_TYPE: 1187 if (FLAG_shared_string_table) { 1188 DCHECK(object.InSharedHeap()); 1189 return true; 1190 } 1191 return false; 1192 case HEAP_NUMBER_TYPE: 1193 return object.InSharedWritableHeap(); 1194 default: 1195 return false; 1196 } 1197} 1198 1199// static 1200MaybeHandle<Object> Object::Share(Isolate* isolate, Handle<Object> value, 1201 ShouldThrow throw_if_cannot_be_shared) { 1202 // Sharing values requires the RO space be shared. 1203 DCHECK(ReadOnlyHeap::IsReadOnlySpaceShared()); 1204 if (value->IsShared()) return value; 1205 return ShareSlow(isolate, Handle<HeapObject>::cast(value), 1206 throw_if_cannot_be_shared); 1207} 1208 1209// https://tc39.es/ecma262/#sec-canbeheldweakly 1210bool Object::CanBeHeldWeakly() const { 1211 if (IsJSReceiver()) { 1212 // TODO(v8:12547) Shared structs and arrays should only be able to point 1213 // to shared values in weak collections. For now, disallow them as weak 1214 // collection keys. 1215 if (FLAG_harmony_struct) { 1216 return !IsJSSharedStruct(); 1217 } 1218 return true; 1219 } 1220 return IsSymbol() && !Symbol::cast(*this).is_in_public_symbol_table(); 1221} 1222 1223Handle<Object> ObjectHashTableShape::AsHandle(Handle<Object> key) { 1224 return key; 1225} 1226 1227Relocatable::Relocatable(Isolate* isolate) { 1228 isolate_ = isolate; 1229 prev_ = isolate->relocatable_top(); 1230 isolate->set_relocatable_top(this); 1231} 1232 1233Relocatable::~Relocatable() { 1234 DCHECK_EQ(isolate_->relocatable_top(), this); 1235 isolate_->set_relocatable_top(prev_); 1236} 1237 1238// Predictably converts HeapObject or Address to uint32 by calculating 1239// offset of the address in respective MemoryChunk. 1240static inline uint32_t ObjectAddressForHashing(Address object) { 1241 uint32_t value = static_cast<uint32_t>(object); 1242 return value & kPageAlignmentMask; 1243} 1244 1245static inline Handle<Object> MakeEntryPair(Isolate* isolate, size_t index, 1246 Handle<Object> value) { 1247 Handle<Object> key = isolate->factory()->SizeToString(index); 1248 Handle<FixedArray> entry_storage = isolate->factory()->NewFixedArray(2); 1249 { 1250 entry_storage->set(0, *key, SKIP_WRITE_BARRIER); 1251 entry_storage->set(1, *value, SKIP_WRITE_BARRIER); 1252 } 1253 return isolate->factory()->NewJSArrayWithElements(entry_storage, 1254 PACKED_ELEMENTS, 2); 1255} 1256 1257static inline Handle<Object> MakeEntryPair(Isolate* isolate, Handle<Object> key, 1258 Handle<Object> value) { 1259 Handle<FixedArray> entry_storage = isolate->factory()->NewFixedArray(2); 1260 { 1261 entry_storage->set(0, *key, SKIP_WRITE_BARRIER); 1262 entry_storage->set(1, *value, SKIP_WRITE_BARRIER); 1263 } 1264 return isolate->factory()->NewJSArrayWithElements(entry_storage, 1265 PACKED_ELEMENTS, 2); 1266} 1267 1268FreshlyAllocatedBigInt FreshlyAllocatedBigInt::cast(Object object) { 1269 SLOW_DCHECK(object.IsBigInt()); 1270 return FreshlyAllocatedBigInt(object.ptr()); 1271} 1272 1273} // namespace internal 1274} // namespace v8 1275 1276#include "src/objects/object-macros-undef.h" 1277 1278#endif // V8_OBJECTS_OBJECTS_INL_H_ 1279