objects-inl.h 37.4 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7 8 9 10
//
// Review notes:
//
// - The use of macros in these inline functions may seem superfluous
// but it is absolutely needed to make sure gcc generates optimal
// code. gcc is not happy when attempting to inline too deep.
//
11

12 13
#ifndef V8_OBJECTS_OBJECTS_INL_H_
#define V8_OBJECTS_OBJECTS_INL_H_
14

15
#include "src/base/bits.h"
16
#include "src/base/memory.h"
17
#include "src/builtins/builtins.h"
18
#include "src/common/external-pointer-inl.h"
19
#include "src/handles/handles-inl.h"
20
#include "src/heap/factory.h"
21
#include "src/heap/heap-write-barrier-inl.h"
22
#include "src/heap/read-only-heap-inl.h"
23 24
#include "src/numbers/conversions.h"
#include "src/numbers/double.h"
25
#include "src/objects/bigint.h"
26
#include "src/objects/heap-number-inl.h"
27
#include "src/objects/heap-object.h"
28
#include "src/objects/js-proxy-inl.h"  // TODO(jkummerow): Drop.
29
#include "src/objects/keys.h"
30
#include "src/objects/literal-objects.h"
31
#include "src/objects/lookup-inl.h"  // TODO(jkummerow): Drop.
32
#include "src/objects/objects.h"
33
#include "src/objects/oddball.h"
34 35
#include "src/objects/property-details.h"
#include "src/objects/property.h"
36
#include "src/objects/regexp-match-info.h"
37
#include "src/objects/scope-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/sanitizer/tsan.h"
46

47 48 49
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"

50 51
namespace v8 {
namespace internal {
52

53
PropertyDetails::PropertyDetails(Smi smi) { value_ = smi.value(); }
54

55
Smi PropertyDetails::AsSmi() const {
56 57 58 59
  // Ensure the upper 2 bits have the same value by sign extending it. This is
  // necessary to be able to use the 31st bit of the property details.
  int value = value_ << 1;
  return Smi::FromInt(value >> 1);
60 61
}

62
int PropertyDetails::field_width_in_words() const {
63
  DCHECK_EQ(location(), kField);
64
  if (!FLAG_unbox_double_fields) return 1;
65 66
  if (kDoubleSize == kTaggedSize) return 1;
  return representation().IsDouble() ? kDoubleSize / kTaggedSize : 1;
67 68
}

69
DEF_GETTER(HeapObject, IsClassBoilerplate, bool) {
70 71
  return IsFixedArrayExact(isolate);
}
72

73 74 75 76
bool Object::IsTaggedIndex() const {
  return IsSmi() && TaggedIndex::IsValid(TaggedIndex(ptr()).value());
}

77 78 79 80
#define IS_TYPE_FUNCTION_DEF(type_)                                      \
  bool Object::Is##type_() const {                                       \
    return IsHeapObject() && HeapObject::cast(*this).Is##type_();        \
  }                                                                      \
81
  bool Object::Is##type_(IsolateRoot isolate) const {                    \
82
    return IsHeapObject() && HeapObject::cast(*this).Is##type_(isolate); \
83
  }
84
HEAP_OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DEF)
85 86
IS_TYPE_FUNCTION_DEF(HashTableBase)
IS_TYPE_FUNCTION_DEF(SmallOrderedHashTable)
87
#undef IS_TYPE_FUNCTION_DEF
88

89 90 91 92
#define IS_TYPE_FUNCTION_DEF(Type, Value)                        \
  bool Object::Is##Type(Isolate* isolate) const {                \
    return Is##Type(ReadOnlyRoots(isolate));                     \
  }                                                              \
93
  bool Object::Is##Type(LocalIsolate* isolate) const {           \
94 95
    return Is##Type(ReadOnlyRoots(isolate));                     \
  }                                                              \
96 97 98 99 100 101 102 103 104
  bool Object::Is##Type(ReadOnlyRoots roots) const {             \
    return *this == roots.Value();                               \
  }                                                              \
  bool Object::Is##Type() const {                                \
    return IsHeapObject() && HeapObject::cast(*this).Is##Type(); \
  }                                                              \
  bool HeapObject::Is##Type(Isolate* isolate) const {            \
    return Object::Is##Type(isolate);                            \
  }                                                              \
105
  bool HeapObject::Is##Type(LocalIsolate* isolate) const {       \
106 107
    return Object::Is##Type(isolate);                            \
  }                                                              \
108 109 110
  bool HeapObject::Is##Type(ReadOnlyRoots roots) const {         \
    return Object::Is##Type(roots);                              \
  }                                                              \
111
  bool HeapObject::Is##Type() const { return Is##Type(GetReadOnlyRoots()); }
112 113
ODDBALL_LIST(IS_TYPE_FUNCTION_DEF)
#undef IS_TYPE_FUNCTION_DEF
114

115 116
bool Object::IsNullOrUndefined(Isolate* isolate) const {
  return IsNullOrUndefined(ReadOnlyRoots(isolate));
117 118
}

119 120
bool Object::IsNullOrUndefined(ReadOnlyRoots roots) const {
  return IsNull(roots) || IsUndefined(roots);
121 122
}

123
bool Object::IsNullOrUndefined() const {
124
  return IsHeapObject() && HeapObject::cast(*this).IsNullOrUndefined();
125 126
}

127 128
bool Object::IsZero() const { return *this == Smi::zero(); }

129 130 131 132 133 134 135
bool Object::IsPublicSymbol() const {
  return IsSymbol() && !Symbol::cast(*this).is_private();
}
bool Object::IsPrivateSymbol() const {
  return IsSymbol() && Symbol::cast(*this).is_private();
}

136 137 138 139
bool Object::IsNoSharedNameSentinel() const {
  return *this == SharedFunctionInfo::kNoSharedNameSentinel;
}

140 141
bool HeapObject::IsNullOrUndefined(Isolate* isolate) const {
  return IsNullOrUndefined(ReadOnlyRoots(isolate));
142 143 144
}

bool HeapObject::IsNullOrUndefined(ReadOnlyRoots roots) const {
145
  return Object::IsNullOrUndefined(roots);
146 147 148
}

bool HeapObject::IsNullOrUndefined() const {
149
  return IsNullOrUndefined(GetReadOnlyRoots());
150 151
}

152
DEF_GETTER(HeapObject, IsUniqueName, bool) {
153
  return IsInternalizedString(isolate) || IsSymbol(isolate);
154 155
}

156
DEF_GETTER(HeapObject, IsFunction, bool) {
157
  return IsJSFunctionOrBoundFunction();
158 159
}

160
DEF_GETTER(HeapObject, IsCallable, bool) { return map(isolate).is_callable(); }
161

162
DEF_GETTER(HeapObject, IsCallableJSProxy, bool) {
163
  return IsCallable(isolate) && IsJSProxy(isolate);
164 165
}

166
DEF_GETTER(HeapObject, IsCallableApiObject, bool) {
167 168
  InstanceType type = map(isolate).instance_type();
  return IsCallable(isolate) &&
169 170 171
         (type == JS_API_OBJECT_TYPE || type == JS_SPECIAL_API_OBJECT_TYPE);
}

172
DEF_GETTER(HeapObject, IsNonNullForeign, bool) {
173 174
  return IsForeign(isolate) &&
         Foreign::cast(*this).foreign_address() != kNullAddress;
175 176
}

177
DEF_GETTER(HeapObject, IsConstructor, bool) {
178 179
  return map(isolate).is_constructor();
}
180

181
DEF_GETTER(HeapObject, IsSourceTextModuleInfo, bool) {
182 183 184
  // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by
  // i::GetIsolateForPtrCompr(HeapObject).
  return map(isolate) == GetReadOnlyRoots(isolate).module_info_map();
185 186
}

187
DEF_GETTER(HeapObject, IsConsString, bool) {
188 189
  if (!IsString(isolate)) return false;
  return StringShape(String::cast(*this).map(isolate)).IsCons();
190 191
}

192
DEF_GETTER(HeapObject, IsThinString, bool) {
193 194
  if (!IsString(isolate)) return false;
  return StringShape(String::cast(*this).map(isolate)).IsThin();
195 196
}

197
DEF_GETTER(HeapObject, IsSlicedString, bool) {
198 199
  if (!IsString(isolate)) return false;
  return StringShape(String::cast(*this).map(isolate)).IsSliced();
200 201
}

202
DEF_GETTER(HeapObject, IsSeqString, bool) {
203 204
  if (!IsString(isolate)) return false;
  return StringShape(String::cast(*this).map(isolate)).IsSequential();
205 206
}

207
DEF_GETTER(HeapObject, IsSeqOneByteString, bool) {
208 209 210
  if (!IsString(isolate)) return false;
  return StringShape(String::cast(*this).map(isolate)).IsSequential() &&
         String::cast(*this).IsOneByteRepresentation(isolate);
211 212
}

213
DEF_GETTER(HeapObject, IsSeqTwoByteString, bool) {
214 215 216
  if (!IsString(isolate)) return false;
  return StringShape(String::cast(*this).map(isolate)).IsSequential() &&
         String::cast(*this).IsTwoByteRepresentation(isolate);
217 218
}

219
DEF_GETTER(HeapObject, IsExternalOneByteString, bool) {
220 221 222
  if (!IsString(isolate)) return false;
  return StringShape(String::cast(*this).map(isolate)).IsExternal() &&
         String::cast(*this).IsOneByteRepresentation(isolate);
223 224
}

225
DEF_GETTER(HeapObject, IsExternalTwoByteString, bool) {
226 227 228
  if (!IsString(isolate)) return false;
  return StringShape(String::cast(*this).map(isolate)).IsExternal() &&
         String::cast(*this).IsTwoByteRepresentation(isolate);
229 230
}

231 232 233
bool Object::IsNumber() const {
  if (IsSmi()) return true;
  HeapObject this_heap_object = HeapObject::cast(*this);
234
  IsolateRoot isolate = GetIsolateForPtrCompr(this_heap_object);
235 236
  return this_heap_object.IsHeapNumber(isolate);
}
237

238
bool Object::IsNumber(IsolateRoot isolate) const {
239 240 241 242 243 244
  return IsSmi() || IsHeapNumber(isolate);
}

bool Object::IsNumeric() const {
  if (IsSmi()) return true;
  HeapObject this_heap_object = HeapObject::cast(*this);
245
  IsolateRoot isolate = GetIsolateForPtrCompr(this_heap_object);
246 247 248
  return this_heap_object.IsHeapNumber(isolate) ||
         this_heap_object.IsBigInt(isolate);
}
249

250
bool Object::IsNumeric(IsolateRoot isolate) const {
251 252 253
  return IsNumber(isolate) || IsBigInt(isolate);
}

254
DEF_GETTER(HeapObject, IsFreeSpaceOrFiller, bool) {
255
  InstanceType instance_type = map(isolate).instance_type();
256
  return instance_type == FREE_SPACE_TYPE || instance_type == FILLER_TYPE;
257 258
}

259
DEF_GETTER(HeapObject, IsFrameArray, bool) {
260
  return IsFixedArrayExact(isolate);
261
}
262

263
DEF_GETTER(HeapObject, IsArrayList, bool) {
264 265 266 267 268 269
  // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by
  // i::GetIsolateForPtrCompr(HeapObject).
  ReadOnlyRoots roots = GetReadOnlyRoots(isolate);
  return *this == roots.empty_fixed_array() ||
         map(isolate) == roots.array_list_map();
}
270

271
DEF_GETTER(HeapObject, IsRegExpMatchInfo, bool) {
272
  return IsFixedArrayExact(isolate);
273
}
274

275 276 277
bool Object::IsLayoutDescriptor() const {
  if (IsSmi()) return true;
  HeapObject this_heap_object = HeapObject::cast(*this);
278
  IsolateRoot isolate = GetIsolateForPtrCompr(this_heap_object);
279 280
  return this_heap_object.IsByteArray(isolate);
}
281

282
bool Object::IsLayoutDescriptor(IsolateRoot isolate) const {
283 284
  return IsSmi() || IsByteArray(isolate);
}
285

286
DEF_GETTER(HeapObject, IsDeoptimizationData, bool) {
287
  // Must be a fixed array.
288
  if (!IsFixedArrayExact(isolate)) return false;
289

290 291 292 293
  // There's no sure way to detect the difference between a fixed array and
  // a deoptimization data array.  Since this is used for asserts we can
  // check that the length is zero or else the fixed size plus a multiple of
  // the entry size.
294
  int length = FixedArray::cast(*this).length();
295
  if (length == 0) return true;
296

297 298
  length -= DeoptimizationData::kFirstDeoptEntryIndex;
  return length >= 0 && length % DeoptimizationData::kDeoptEntrySize == 0;
299 300
}

301
DEF_GETTER(HeapObject, IsHandlerTable, bool) {
302
  if (!IsFixedArrayExact(isolate)) return false;
303 304 305
  // There's actually no way to see the difference between a fixed array and
  // a handler table array.
  return true;
306 307
}

308
DEF_GETTER(HeapObject, IsTemplateList, bool) {
309
  if (!IsFixedArrayExact(isolate)) return false;
310 311
  // There's actually no way to see the difference between a fixed array and
  // a template list.
312
  if (FixedArray::cast(*this).length() < 1) return false;
313
  return true;
314 315
}

316
DEF_GETTER(HeapObject, IsDependentCode, bool) {
317
  if (!IsWeakFixedArray(isolate)) return false;
318 319
  // There's actually no way to see the difference between a weak fixed array
  // and a dependent codes array.
320
  return true;
321 322
}

323 324 325 326 327 328 329
DEF_GETTER(HeapObject, IsOSROptimizedCodeCache, bool) {
  if (!IsWeakFixedArray(isolate)) return false;
  // There's actually no way to see the difference between a weak fixed array
  // and a osr optimized code cache.
  return true;
}

330
DEF_GETTER(HeapObject, IsAbstractCode, bool) {
331
  return IsBytecodeArray(isolate) || IsCode(isolate);
332 333
}

334
DEF_GETTER(HeapObject, IsStringWrapper, bool) {
335 336
  return IsJSPrimitiveWrapper(isolate) &&
         JSPrimitiveWrapper::cast(*this).value().IsString(isolate);
337
}
338

339
DEF_GETTER(HeapObject, IsBooleanWrapper, bool) {
340 341
  return IsJSPrimitiveWrapper(isolate) &&
         JSPrimitiveWrapper::cast(*this).value().IsBoolean(isolate);
342 343
}

344
DEF_GETTER(HeapObject, IsScriptWrapper, bool) {
345 346
  return IsJSPrimitiveWrapper(isolate) &&
         JSPrimitiveWrapper::cast(*this).value().IsScript(isolate);
347 348
}

349
DEF_GETTER(HeapObject, IsNumberWrapper, bool) {
350 351
  return IsJSPrimitiveWrapper(isolate) &&
         JSPrimitiveWrapper::cast(*this).value().IsNumber(isolate);
352 353
}

354
DEF_GETTER(HeapObject, IsBigIntWrapper, bool) {
355 356
  return IsJSPrimitiveWrapper(isolate) &&
         JSPrimitiveWrapper::cast(*this).value().IsBigInt(isolate);
357 358
}

359
DEF_GETTER(HeapObject, IsSymbolWrapper, bool) {
360 361
  return IsJSPrimitiveWrapper(isolate) &&
         JSPrimitiveWrapper::cast(*this).value().IsSymbol(isolate);
362 363
}

364
DEF_GETTER(HeapObject, IsStringSet, bool) { return IsHashTable(isolate); }
365

366
DEF_GETTER(HeapObject, IsObjectHashSet, bool) { return IsHashTable(isolate); }
367

368
DEF_GETTER(HeapObject, IsCompilationCacheTable, bool) {
369 370
  return IsHashTable(isolate);
}
371

372
DEF_GETTER(HeapObject, IsMapCache, bool) { return IsHashTable(isolate); }
373

374
DEF_GETTER(HeapObject, IsObjectHashTable, bool) { return IsHashTable(isolate); }
375

376
DEF_GETTER(HeapObject, IsHashTableBase, bool) { return IsHashTable(isolate); }
377

378 379 380 381 382 383
DEF_GETTER(HeapObject, IsWasmExceptionPackage, bool) {
  // It is not possible to check for the existence of certain properties on the
  // underlying {JSReceiver} here because that requires calling handlified code.
  return IsJSReceiver(isolate);
}

384
bool Object::IsPrimitive() const {
385 386
  if (IsSmi()) return true;
  HeapObject this_heap_object = HeapObject::cast(*this);
387
  IsolateRoot isolate = GetIsolateForPtrCompr(this_heap_object);
388 389 390
  return this_heap_object.map(isolate).IsPrimitiveMap();
}

391
bool Object::IsPrimitive(IsolateRoot isolate) const {
392
  return IsSmi() || HeapObject::cast(*this).map(isolate).IsPrimitiveMap();
393
}
394

395 396 397 398 399 400 401 402 403
// static
Maybe<bool> Object::IsArray(Handle<Object> object) {
  if (object->IsSmi()) return Just(false);
  Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
  if (heap_object->IsJSArray()) return Just(true);
  if (!heap_object->IsJSProxy()) return Just(false);
  return JSProxy::IsArray(Handle<JSProxy>::cast(object));
}

404
DEF_GETTER(HeapObject, IsUndetectable, bool) {
405 406
  return map(isolate).is_undetectable();
}
407

408
DEF_GETTER(HeapObject, IsAccessCheckNeeded, bool) {
409
  if (IsJSGlobalProxy(isolate)) {
410
    const JSGlobalProxy proxy = JSGlobalProxy::cast(*this);
411 412
    JSGlobalObject global = proxy.GetIsolate()->context().global_object();
    return proxy.IsDetachedFrom(global);
413
  }
414
  return map(isolate).is_access_check_needed();
415
}
416

417 418 419 420
#define MAKE_STRUCT_PREDICATE(NAME, Name, name)                         \
  bool Object::Is##Name() const {                                       \
    return IsHeapObject() && HeapObject::cast(*this).Is##Name();        \
  }                                                                     \
421
  bool Object::Is##Name(IsolateRoot isolate) const {                    \
422
    return IsHeapObject() && HeapObject::cast(*this).Is##Name(isolate); \
423
  }
424 425
STRUCT_LIST(MAKE_STRUCT_PREDICATE)
#undef MAKE_STRUCT_PREDICATE
426

427 428
double Object::Number() const {
  DCHECK(IsNumber());
429 430
  return IsSmi() ? static_cast<double>(Smi(this->ptr()).value())
                 : HeapNumber::unchecked_cast(*this).value();
431
}
432

433 434 435 436 437 438 439 440 441 442
// static
bool Object::SameNumberValue(double value1, double value2) {
  // SameNumberValue(NaN, NaN) is true.
  if (value1 != value2) {
    return std::isnan(value1) && std::isnan(value2);
  }
  // SameNumberValue(0.0, -0.0) is false.
  return (std::signbit(value1) == std::signbit(value2));
}

443
bool Object::IsNaN() const {
444
  return this->IsHeapNumber() && std::isnan(HeapNumber::cast(*this).value());
445
}
446

447 448
bool Object::IsMinusZero() const {
  return this->IsHeapNumber() &&
449
         i::IsMinusZero(HeapNumber::cast(*this).value());
450
}
451

452
OBJECT_CONSTRUCTORS_IMPL(RegExpMatchInfo, FixedArray)
453
OBJECT_CONSTRUCTORS_IMPL(BigIntBase, PrimitiveHeapObject)
454 455 456
OBJECT_CONSTRUCTORS_IMPL(BigInt, BigIntBase)
OBJECT_CONSTRUCTORS_IMPL(FreshlyAllocatedBigInt, BigIntBase)

457 458
// ------------------------------------
// Cast operations
459

460
CAST_ACCESSOR(BigIntBase)
461 462
CAST_ACCESSOR(BigInt)
CAST_ACCESSOR(RegExpMatchInfo)
463

464
bool Object::HasValidElements() {
465 466 467
  // Dictionary is covered under FixedArray. ByteArray is used
  // for the JSTypedArray backing stores.
  return IsFixedArray() || IsFixedDoubleArray() || IsByteArray();
468 469
}

470
bool Object::FilterKey(PropertyFilter filter) {
471
  DCHECK(!IsPropertyCell());
472 473
  if (filter == PRIVATE_NAMES_ONLY) {
    if (!IsSymbol()) return true;
474
    return !Symbol::cast(*this).is_private_name();
475
  } else if (IsSymbol()) {
476
    if (filter & SKIP_SYMBOLS) return true;
477

478
    if (Symbol::cast(*this).is_private()) return true;
479 480 481 482
  } else {
    if (filter & SKIP_STRINGS) return true;
  }
  return false;
483 484
}

485
Representation Object::OptimalRepresentation(IsolateRoot isolate) const {
486 487 488
  if (!FLAG_track_fields) return Representation::Tagged();
  if (IsSmi()) {
    return Representation::Smi();
489 490 491
  }
  HeapObject heap_object = HeapObject::cast(*this);
  if (FLAG_track_double_fields && heap_object.IsHeapNumber(isolate)) {
492
    return Representation::Double();
493 494 495
  } else if (FLAG_track_computed_fields &&
             heap_object.IsUninitialized(
                 heap_object.GetReadOnlyRoots(isolate))) {
496 497 498 499 500 501 502 503
    return Representation::None();
  } else if (FLAG_track_heap_object_fields) {
    return Representation::HeapObject();
  } else {
    return Representation::Tagged();
  }
}

504
ElementsKind Object::OptimalElementsKind(IsolateRoot isolate) const {
505
  if (IsSmi()) return PACKED_SMI_ELEMENTS;
506
  if (IsNumber(isolate)) return PACKED_DOUBLE_ELEMENTS;
507
  return PACKED_ELEMENTS;
508 509 510
}

bool Object::FitsRepresentation(Representation representation) {
511
  if (FLAG_track_fields && representation.IsSmi()) {
512 513
    return IsSmi();
  } else if (FLAG_track_double_fields && representation.IsDouble()) {
514
    return IsNumber();
515 516
  } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
    return IsHeapObject();
517 518
  } else if (FLAG_track_fields && representation.IsNone()) {
    return false;
519 520 521 522
  }
  return true;
}

523
bool Object::ToUint32(uint32_t* value) const {
524
  if (IsSmi()) {
525
    int num = Smi::ToInt(*this);
526 527 528 529 530
    if (num < 0) return false;
    *value = static_cast<uint32_t>(num);
    return true;
  }
  if (IsHeapNumber()) {
531
    double num = HeapNumber::cast(*this).value();
532
    return DoubleToUint32IfEqualToSelf(num, value);
533 534 535
  }
  return false;
}
536

537
// static
538
MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
539 540
                                         Handle<Object> object,
                                         const char* method_name) {
541
  if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
542
  return ToObjectImpl(isolate, object, method_name);
543 544
}

545 546 547 548 549 550
// static
MaybeHandle<Name> Object::ToName(Isolate* isolate, Handle<Object> input) {
  if (input->IsName()) return Handle<Name>::cast(input);
  return ConvertToName(isolate, input);
}

551 552 553
// static
MaybeHandle<Object> Object::ToPropertyKey(Isolate* isolate,
                                          Handle<Object> value) {
554
  if (value->IsSmi() || HeapObject::cast(*value).IsName()) return value;
555 556 557
  return ConvertToPropertyKey(isolate, value);
}

558 559 560 561 562 563 564
// static
MaybeHandle<Object> Object::ToPrimitive(Handle<Object> input,
                                        ToPrimitiveHint hint) {
  if (input->IsPrimitive()) return input;
  return JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input), hint);
}

565
// static
566
MaybeHandle<Object> Object::ToNumber(Isolate* isolate, Handle<Object> input) {
567
  if (input->IsNumber()) return input;  // Shortcut.
568
  return ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber);
569 570 571
}

// static
572
MaybeHandle<Object> Object::ToNumeric(Isolate* isolate, Handle<Object> input) {
573
  if (input->IsNumber() || input->IsBigInt()) return input;  // Shortcut.
574
  return ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumeric);
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
}

// static
MaybeHandle<Object> Object::ToInteger(Isolate* isolate, Handle<Object> input) {
  if (input->IsSmi()) return input;
  return ConvertToInteger(isolate, input);
}

// static
MaybeHandle<Object> Object::ToInt32(Isolate* isolate, Handle<Object> input) {
  if (input->IsSmi()) return input;
  return ConvertToInt32(isolate, input);
}

// static
MaybeHandle<Object> Object::ToUint32(Isolate* isolate, Handle<Object> input) {
591
  if (input->IsSmi()) return handle(Smi::cast(*input).ToUint32Smi(), isolate);
592 593 594 595 596 597 598 599
  return ConvertToUint32(isolate, input);
}

// static
MaybeHandle<String> Object::ToString(Isolate* isolate, Handle<Object> input) {
  if (input->IsString()) return Handle<String>::cast(input);
  return ConvertToString(isolate, input);
}
600

601 602 603
// static
MaybeHandle<Object> Object::ToLength(Isolate* isolate, Handle<Object> input) {
  if (input->IsSmi()) {
jgruber's avatar
jgruber committed
604
    int value = std::max(Smi::ToInt(*input), 0);
605 606 607 608 609 610 611
    return handle(Smi::FromInt(value), isolate);
  }
  return ConvertToLength(isolate, input);
}

// static
MaybeHandle<Object> Object::ToIndex(Isolate* isolate, Handle<Object> input,
612
                                    MessageTemplate error_index) {
jgruber's avatar
jgruber committed
613
  if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input;
614 615 616
  return ConvertToIndex(isolate, input, error_index);
}

617
MaybeHandle<Object> Object::GetProperty(Isolate* isolate, Handle<Object> object,
618
                                        Handle<Name> name) {
619
  LookupIterator it(isolate, object, name);
620
  if (!it.IsFound()) return it.factory()->undefined_value();
621
  return GetProperty(&it);
622 623
}

624
MaybeHandle<Object> Object::GetElement(Isolate* isolate, Handle<Object> object,
625
                                       uint32_t index) {
626
  LookupIterator it(isolate, object, index);
627
  if (!it.IsFound()) return it.factory()->undefined_value();
628
  return GetProperty(&it);
629 630
}

631 632
MaybeHandle<Object> Object::SetElement(Isolate* isolate, Handle<Object> object,
                                       uint32_t index, Handle<Object> value,
633
                                       ShouldThrow should_throw) {
634
  LookupIterator it(isolate, object, index);
635
  MAYBE_RETURN_NULL(
636
      SetProperty(&it, value, StoreOrigin::kMaybeKeyed, Just(should_throw)));
637
  return value;
638 639
}

640 641 642 643 644
void Object::InitExternalPointerField(size_t offset, Isolate* isolate) {
  i::InitExternalPointerField(field_address(offset), isolate);
}

void Object::InitExternalPointerField(size_t offset, Isolate* isolate,
645 646
                                      Address value, ExternalPointerTag tag) {
  i::InitExternalPointerField(field_address(offset), isolate, value, tag);
647 648
}

649 650 651
Address Object::ReadExternalPointerField(size_t offset, IsolateRoot isolate,
                                         ExternalPointerTag tag) const {
  return i::ReadExternalPointerField(field_address(offset), isolate, tag);
652 653 654
}

void Object::WriteExternalPointerField(size_t offset, Isolate* isolate,
655 656
                                       Address value, ExternalPointerTag tag) {
  i::WriteExternalPointerField(field_address(offset), isolate, value, tag);
657 658
}

659
ObjectSlot HeapObject::RawField(int byte_offset) const {
660
  return ObjectSlot(field_address(byte_offset));
661 662 663
}

MaybeObjectSlot HeapObject::RawMaybeWeakField(int byte_offset) const {
664
  return MaybeObjectSlot(field_address(byte_offset));
665 666
}

667
MapWord MapWord::FromMap(const Map map) { return MapWord(map.ptr()); }
668

669
Map MapWord::ToMap() const { return Map::unchecked_cast(Object(value_)); }
670

671
bool MapWord::IsForwardingAddress() const { return HAS_SMI_TAG(value_); }
672

673
MapWord MapWord::FromForwardingAddress(HeapObject object) {
674
  return MapWord(object.ptr() - kHeapObjectTag);
675 676
}

677
HeapObject MapWord::ToForwardingAddress() {
678
  DCHECK(IsForwardingAddress());
679
  return HeapObject::FromAddress(value_);
680 681
}

682
#ifdef VERIFY_HEAP
683
void HeapObject::VerifyObjectField(Isolate* isolate, int offset) {
684
  VerifyPointer(isolate, TaggedField<Object>::load(isolate, *this, offset));
685
  STATIC_ASSERT(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size);
686
}
687

688
void HeapObject::VerifyMaybeObjectField(Isolate* isolate, int offset) {
689 690
  MaybeObject::VerifyMaybeObjectPointer(
      isolate, TaggedField<MaybeObject>::load(isolate, *this, offset));
691
  STATIC_ASSERT(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size);
692 693
}

694
void HeapObject::VerifySmiField(int offset) {
695
  CHECK(TaggedField<Object>::load(*this, offset).IsSmi());
696
  STATIC_ASSERT(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size);
697
}
698

699 700
#endif

701
ReadOnlyRoots HeapObject::GetReadOnlyRoots() const {
702
  return ReadOnlyHeap::GetReadOnlyRoots(*this);
703 704
}

705
ReadOnlyRoots HeapObject::GetReadOnlyRoots(IsolateRoot isolate) const {
706
#ifdef V8_COMPRESS_POINTERS
707 708
  DCHECK_NE(isolate.address(), 0);
  return ReadOnlyRoots(Isolate::FromRootAddress(isolate.address()));
709 710 711 712 713
#else
  return GetReadOnlyRoots();
#endif
}

714
DEF_GETTER(HeapObject, map, Map) { return map_word(isolate).ToMap(); }
715

716
void HeapObject::set_map(Map value) {
717
#ifdef VERIFY_HEAP
718
  if (FLAG_verify_heap && !value.is_null()) {
719
    GetHeapFromWritableObject(*this)->VerifyObjectLayoutChange(*this, value);
720
  }
721
#endif
722
  set_map_word(MapWord::FromMap(value));
723
#ifndef V8_DISABLE_WRITE_BARRIERS
724
  if (!value.is_null()) {
725 726
    // TODO(1600) We are passing kNullAddress as a slot because maps can never
    // be on an evacuation candidate.
727
    WriteBarrier::Marking(*this, ObjectSlot(kNullAddress), value);
728
  }
729
#endif
730 731
}

732 733
DEF_GETTER(HeapObject, synchronized_map, Map) {
  return synchronized_map_word(isolate).ToMap();
734 735
}

736
void HeapObject::synchronized_set_map(Map value) {
737
#ifdef VERIFY_HEAP
738
  if (FLAG_verify_heap && !value.is_null()) {
739
    GetHeapFromWritableObject(*this)->VerifyObjectLayoutChange(*this, value);
740
  }
741
#endif
742
  synchronized_set_map_word(MapWord::FromMap(value));
743
#ifndef V8_DISABLE_WRITE_BARRIERS
744
  if (!value.is_null()) {
745 746
    // TODO(1600) We are passing kNullAddress as a slot because maps can never
    // be on an evacuation candidate.
747
    WriteBarrier::Marking(*this, ObjectSlot(kNullAddress), value);
748
  }
749
#endif
750 751
}

752
// Unsafe accessor omitting write barrier.
753
void HeapObject::set_map_no_write_barrier(Map value) {
754
#ifdef VERIFY_HEAP
755
  if (FLAG_verify_heap && !value.is_null()) {
756
    GetHeapFromWritableObject(*this)->VerifyObjectLayoutChange(*this, value);
757
  }
758
#endif
759 760 761
  set_map_word(MapWord::FromMap(value));
}

762
void HeapObject::set_map_after_allocation(Map value, WriteBarrierMode mode) {
763
  set_map_word(MapWord::FromMap(value));
764
#ifndef V8_DISABLE_WRITE_BARRIERS
765
  if (mode != SKIP_WRITE_BARRIER) {
766
    DCHECK(!value.is_null());
767 768
    // TODO(1600) We are passing kNullAddress as a slot because maps can never
    // be on an evacuation candidate.
769
    WriteBarrier::Marking(*this, ObjectSlot(kNullAddress), value);
770
  }
771
#endif
772 773
}

774 775
ObjectSlot HeapObject::map_slot() const {
  return ObjectSlot(MapField::address(*this));
776
}
777

778
DEF_GETTER(HeapObject, map_word, MapWord) {
779 780
  return MapField::Relaxed_Load(isolate, *this);
}
781

782
void HeapObject::set_map_word(MapWord map_word) {
783
  MapField::Relaxed_Store(*this, map_word);
784 785
}

786 787
DEF_GETTER(HeapObject, synchronized_map_word, MapWord) {
  return MapField::Acquire_Load(isolate, *this);
788 789 790
}

void HeapObject::synchronized_set_map_word(MapWord map_word) {
791 792 793
  MapField::Release_Store(*this, map_word);
}

794 795
bool HeapObject::release_compare_and_swap_map_word(MapWord old_map_word,
                                                   MapWord new_map_word) {
796 797 798
  Tagged_t result =
      MapField::Release_CompareAndSwap(*this, old_map_word, new_map_word);
  return result == static_cast<Tagged_t>(old_map_word.ptr());
799
}
800

801
int HeapObject::Size() const { return SizeFromMap(map()); }
802

803 804 805
inline bool IsSpecialReceiverInstanceType(InstanceType instance_type) {
  return instance_type <= LAST_SPECIAL_RECEIVER_TYPE;
}
806

807 808 809 810 811 812 813 814 815
// This should be in objects/map-inl.h, but can't, because of a cyclic
// dependency.
bool Map::IsSpecialReceiverMap() const {
  bool result = IsSpecialReceiverInstanceType(instance_type());
  DCHECK_IMPLIES(!result,
                 !has_named_interceptor() && !is_access_check_needed());
  return result;
}

816 817 818 819 820 821 822 823 824 825
inline bool IsCustomElementsReceiverInstanceType(InstanceType instance_type) {
  return instance_type <= LAST_CUSTOM_ELEMENTS_RECEIVER;
}

// This should be in objects/map-inl.h, but can't, because of a cyclic
// dependency.
bool Map::IsCustomElementsReceiverMap() const {
  return IsCustomElementsReceiverInstanceType(instance_type());
}

826 827 828
bool Object::ToArrayLength(uint32_t* index) const {
  return Object::ToUint32(index);
}
829

830
bool Object::ToArrayIndex(uint32_t* index) const {
831
  return Object::ToUint32(index) && *index != kMaxUInt32;
832 833
}

834 835 836 837 838 839 840 841 842 843
bool Object::ToIntegerIndex(size_t* index) const {
  if (IsSmi()) {
    int num = Smi::ToInt(*this);
    if (num < 0) return false;
    *index = static_cast<size_t>(num);
    return true;
  }
  if (IsHeapNumber()) {
    double num = HeapNumber::cast(*this).value();
    if (!(num >= 0)) return false;  // Negation to catch NaNs.
844 845 846 847 848
    constexpr double max =
        std::min(kMaxSafeInteger,
                 // The maximum size_t is reserved as "invalid" sentinel.
                 static_cast<double>(std::numeric_limits<size_t>::max() - 1));
    if (num > max) return false;
849 850 851 852 853 854 855 856
    size_t result = static_cast<size_t>(num);
    if (num != result) return false;  // Conversion lost fractional precision.
    *index = result;
    return true;
  }
  return false;
}

857 858
int RegExpMatchInfo::NumberOfCaptureRegisters() {
  DCHECK_GE(length(), kLastMatchOverhead);
859
  Object obj = get(kNumberOfCapturesIndex);
jgruber's avatar
jgruber committed
860
  return Smi::ToInt(obj);
861 862 863 864 865 866 867
}

void RegExpMatchInfo::SetNumberOfCaptureRegisters(int value) {
  DCHECK_GE(length(), kLastMatchOverhead);
  set(kNumberOfCapturesIndex, Smi::FromInt(value));
}

868
String RegExpMatchInfo::LastSubject() {
869
  DCHECK_GE(length(), kLastMatchOverhead);
870
  return String::cast(get(kLastSubjectIndex));
871 872
}

873
void RegExpMatchInfo::SetLastSubject(String value) {
874 875 876 877
  DCHECK_GE(length(), kLastMatchOverhead);
  set(kLastSubjectIndex, value);
}

878
Object RegExpMatchInfo::LastInput() {
879 880 881 882
  DCHECK_GE(length(), kLastMatchOverhead);
  return get(kLastInputIndex);
}

883
void RegExpMatchInfo::SetLastInput(Object value) {
884 885 886 887 888 889
  DCHECK_GE(length(), kLastMatchOverhead);
  set(kLastInputIndex, value);
}

int RegExpMatchInfo::Capture(int i) {
  DCHECK_LT(i, NumberOfCaptureRegisters());
890
  Object obj = get(kFirstCaptureIndex + i);
jgruber's avatar
jgruber committed
891
  return Smi::ToInt(obj);
892 893 894 895 896 897
}

void RegExpMatchInfo::SetCapture(int i, int value) {
  DCHECK_LT(i, NumberOfCaptureRegisters());
  set(kFirstCaptureIndex + i, Smi::FromInt(value));
}
898

899
WriteBarrierMode HeapObject::GetWriteBarrierMode(
900
    const DisallowGarbageCollection& promise) {
901
  return GetWriteBarrierModeForObject(*this, &promise);
902 903
}

904
// static
905
AllocationAlignment HeapObject::RequiredAlignment(Map map) {
906 907 908
  // TODO(bmeurer, v8:4153): We should think about requiring double alignment
  // in general for ByteArray, since they are used as backing store for typed
  // arrays now.
909 910 911 912 913 914
#ifdef V8_COMPRESS_POINTERS
  // TODO(ishell, v8:8875): Consider using aligned allocations once the
  // allocation alignment inconsistency is fixed. For now we keep using
  // unaligned access since both x64 and arm64 architectures (where pointer
  // compression is supported) allow unaligned access to doubles and full words.
#endif  // V8_COMPRESS_POINTERS
915
#ifdef V8_HOST_ARCH_32_BIT
916
  int instance_type = map.instance_type();
917
  if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) return kDoubleAligned;
918
  if (instance_type == HEAP_NUMBER_TYPE) return kDoubleUnaligned;
919
#endif  // V8_HOST_ARCH_32_BIT
920
  return kWordAligned;
921 922
}

923
Address HeapObject::GetFieldAddress(int field_offset) const {
924
  return field_address(field_offset);
925 926
}

927
// static
928 929 930
Maybe<bool> Object::GreaterThan(Isolate* isolate, Handle<Object> x,
                                Handle<Object> y) {
  Maybe<ComparisonResult> result = Compare(isolate, x, y);
931 932 933 934 935 936 937 938 939 940 941 942 943 944
  if (result.IsJust()) {
    switch (result.FromJust()) {
      case ComparisonResult::kGreaterThan:
        return Just(true);
      case ComparisonResult::kLessThan:
      case ComparisonResult::kEqual:
      case ComparisonResult::kUndefined:
        return Just(false);
    }
  }
  return Nothing<bool>();
}

// static
945 946 947
Maybe<bool> Object::GreaterThanOrEqual(Isolate* isolate, Handle<Object> x,
                                       Handle<Object> y) {
  Maybe<ComparisonResult> result = Compare(isolate, x, y);
948 949 950 951 952 953 954 955 956 957 958 959 960 961
  if (result.IsJust()) {
    switch (result.FromJust()) {
      case ComparisonResult::kEqual:
      case ComparisonResult::kGreaterThan:
        return Just(true);
      case ComparisonResult::kLessThan:
      case ComparisonResult::kUndefined:
        return Just(false);
    }
  }
  return Nothing<bool>();
}

// static
962 963 964
Maybe<bool> Object::LessThan(Isolate* isolate, Handle<Object> x,
                             Handle<Object> y) {
  Maybe<ComparisonResult> result = Compare(isolate, x, y);
965 966 967 968 969 970 971 972 973 974 975 976 977 978
  if (result.IsJust()) {
    switch (result.FromJust()) {
      case ComparisonResult::kLessThan:
        return Just(true);
      case ComparisonResult::kEqual:
      case ComparisonResult::kGreaterThan:
      case ComparisonResult::kUndefined:
        return Just(false);
    }
  }
  return Nothing<bool>();
}

// static
979 980 981
Maybe<bool> Object::LessThanOrEqual(Isolate* isolate, Handle<Object> x,
                                    Handle<Object> y) {
  Maybe<ComparisonResult> result = Compare(isolate, x, y);
982 983 984 985 986 987 988 989 990 991 992 993 994
  if (result.IsJust()) {
    switch (result.FromJust()) {
      case ComparisonResult::kEqual:
      case ComparisonResult::kLessThan:
        return Just(true);
      case ComparisonResult::kGreaterThan:
      case ComparisonResult::kUndefined:
        return Just(false);
    }
  }
  return Nothing<bool>();
}

995 996
MaybeHandle<Object> Object::GetPropertyOrElement(Isolate* isolate,
                                                 Handle<Object> object,
997
                                                 Handle<Name> name) {
998 999
  LookupIterator::Key key(isolate, name);
  LookupIterator it(isolate, object, key);
1000
  return GetProperty(&it);
1001 1002
}

1003 1004
MaybeHandle<Object> Object::SetPropertyOrElement(
    Isolate* isolate, Handle<Object> object, Handle<Name> name,
1005
    Handle<Object> value, Maybe<ShouldThrow> should_throw,
1006
    StoreOrigin store_origin) {
1007 1008
  LookupIterator::Key key(isolate, name);
  LookupIterator it(isolate, object, key);
1009
  MAYBE_RETURN_NULL(SetProperty(&it, value, store_origin, should_throw));
1010 1011 1012
  return value;
}

1013
MaybeHandle<Object> Object::GetPropertyOrElement(Handle<Object> receiver,
1014
                                                 Handle<Name> name,
1015
                                                 Handle<JSReceiver> holder) {
1016 1017 1018
  Isolate* isolate = holder->GetIsolate();
  LookupIterator::Key key(isolate, name);
  LookupIterator it(isolate, receiver, key, holder);
1019
  return GetProperty(&it);
1020 1021
}

1022
// static
1023
Object Object::GetSimpleHash(Object object) {
1024
  DisallowGarbageCollection no_gc;
1025
  if (object.IsSmi()) {
1026
    uint32_t hash = ComputeUnseededHash(Smi::ToInt(object));
1027 1028
    return Smi::FromInt(hash & Smi::kMaxValue);
  }
1029 1030
  if (object.IsHeapNumber()) {
    double num = HeapNumber::cast(object).value();
1031
    if (std::isnan(num)) return Smi::FromInt(Smi::kMaxValue);
1032
    // Use ComputeUnseededHash for all values in Signed32 range, including -0,
1033 1034 1035 1036
    // which is considered equal to 0 because collections use SameValueZero.
    uint32_t hash;
    // Check range before conversion to avoid undefined behavior.
    if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) {
1037
      hash = ComputeUnseededHash(FastD2I(num));
1038 1039 1040 1041 1042
    } else {
      hash = ComputeLongHash(double_to_uint64(num));
    }
    return Smi::FromInt(hash & Smi::kMaxValue);
  }
1043
  if (object.IsName()) {
1044
    uint32_t hash = Name::cast(object).EnsureHash();
1045 1046
    return Smi::FromInt(hash);
  }
1047
  if (object.IsOddball()) {
1048
    uint32_t hash = Oddball::cast(object).to_string().EnsureHash();
1049 1050
    return Smi::FromInt(hash);
  }
1051 1052
  if (object.IsBigInt()) {
    uint32_t hash = BigInt::cast(object).Hash();
1053 1054
    return Smi::FromInt(hash & Smi::kMaxValue);
  }
1055 1056
  if (object.IsSharedFunctionInfo()) {
    uint32_t hash = SharedFunctionInfo::cast(object).Hash();
1057 1058
    return Smi::FromInt(hash & Smi::kMaxValue);
  }
1059
  DCHECK(object.IsJSReceiver());
1060 1061 1062
  return object;
}

1063
Object Object::GetHash() {
1064
  DisallowGarbageCollection no_gc;
1065
  Object hash = GetSimpleHash(*this);
1066
  if (hash.IsSmi()) return hash;
1067 1068

  DCHECK(IsJSReceiver());
1069
  JSReceiver receiver = JSReceiver::cast(*this);
1070
  return receiver.GetIdentityHash();
1071
}
1072

1073
Handle<Object> ObjectHashTableShape::AsHandle(Handle<Object> key) {
1074 1075 1076
  return key;
}

1077 1078 1079 1080 1081 1082 1083
Relocatable::Relocatable(Isolate* isolate) {
  isolate_ = isolate;
  prev_ = isolate->relocatable_top();
  isolate->set_relocatable_top(this);
}

Relocatable::~Relocatable() {
1084
  DCHECK_EQ(isolate_->relocatable_top(), this);
1085
  isolate_->set_relocatable_top(prev_);
1086 1087
}

1088
// Predictably converts HeapObject or Address to uint32 by calculating
1089
// offset of the address in respective MemoryChunk.
1090 1091
static inline uint32_t ObjectAddressForHashing(Address object) {
  uint32_t value = static_cast<uint32_t>(object);
1092
  return value & kPageAlignmentMask;
1093 1094
}

1095
static inline Handle<Object> MakeEntryPair(Isolate* isolate, size_t index,
1096
                                           Handle<Object> value) {
1097
  Handle<Object> key = isolate->factory()->SizeToString(index);
1098 1099 1100 1101 1102 1103 1104
  Handle<FixedArray> entry_storage =
      isolate->factory()->NewUninitializedFixedArray(2);
  {
    entry_storage->set(0, *key, SKIP_WRITE_BARRIER);
    entry_storage->set(1, *value, SKIP_WRITE_BARRIER);
  }
  return isolate->factory()->NewJSArrayWithElements(entry_storage,
1105
                                                    PACKED_ELEMENTS, 2);
1106 1107
}

1108
static inline Handle<Object> MakeEntryPair(Isolate* isolate, Handle<Object> key,
1109 1110 1111 1112 1113 1114 1115 1116
                                           Handle<Object> value) {
  Handle<FixedArray> entry_storage =
      isolate->factory()->NewUninitializedFixedArray(2);
  {
    entry_storage->set(0, *key, SKIP_WRITE_BARRIER);
    entry_storage->set(1, *value, SKIP_WRITE_BARRIER);
  }
  return isolate->factory()->NewJSArrayWithElements(entry_storage,
1117
                                                    PACKED_ELEMENTS, 2);
1118
}
1119

1120
FreshlyAllocatedBigInt FreshlyAllocatedBigInt::cast(Object object) {
1121 1122
  SLOW_DCHECK(object.IsBigInt());
  return FreshlyAllocatedBigInt(object.ptr());
1123 1124
}

1125 1126
}  // namespace internal
}  // namespace v8
1127

1128 1129
#include "src/objects/object-macros-undef.h"

1130
#endif  // V8_OBJECTS_OBJECTS_INL_H_