js-heap-broker.cc 89.1 KB
Newer Older
1 2 3 4 5
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/compiler/js-heap-broker.h"
6

7
#include "src/ast/modules.h"
8
#include "src/bootstrapper.h"
9
#include "src/boxed-float.h"
10
#include "src/code-factory.h"
11
#include "src/compiler/graph-reducer.h"
12
#include "src/compiler/per-isolate-compiler-cache.h"
13
#include "src/objects-inl.h"
14
#include "src/objects/js-array-buffer-inl.h"
15
#include "src/objects/js-array-inl.h"
16
#include "src/objects/js-regexp-inl.h"
17
#include "src/objects/module-inl.h"
18
#include "src/utils.h"
19 20 21 22 23

namespace v8 {
namespace internal {
namespace compiler {

24 25 26 27
#define FORWARD_DECL(Name) class Name##Data;
HEAP_BROKER_OBJECT_LIST(FORWARD_DECL)
#undef FORWARD_DECL

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
// There are three kinds of ObjectData values.
//
// kSmi: The underlying V8 object is a Smi and the data is an instance of the
//   base class (ObjectData), i.e. it's basically just the handle.  Because the
//   object is a Smi, it's safe to access the handle in order to extract the
//   number value, and AsSmi() does exactly that.
//
// kSerializedHeapObject: The underlying V8 object is a HeapObject and the
//   data is an instance of the corresponding (most-specific) subclass, e.g.
//   JSFunctionData, which provides serialized information about the object.
//
// kUnserializedHeapObject: The underlying V8 object is a HeapObject and the
//   data is an instance of the base class (ObjectData), i.e. it basically
//   carries no information other than the handle.
//
enum ObjectDataKind { kSmi, kSerializedHeapObject, kUnserializedHeapObject };

45 46
class ObjectData : public ZoneObject {
 public:
47
  ObjectData(JSHeapBroker* broker, ObjectData** storage, Handle<Object> object,
48
             ObjectDataKind kind)
49
      : object_(object), kind_(kind) {
50 51
    // This assignment ensures we don't end up inserting the same object
    // in an endless recursion.
52 53 54 55 56 57 58 59 60
    *storage = this;

    broker->Trace("Creating data %p for handle %" V8PRIuPTR " (", this,
                  object.address());
    if (FLAG_trace_heap_broker) {
      object->ShortPrint();
      PrintF(")\n");
    }
    CHECK_NOT_NULL(broker->isolate()->handle_scope_data()->canonical_scope);
61 62 63 64 65 66 67 68
  }

#define DECLARE_IS_AND_AS(Name) \
  bool Is##Name() const;        \
  Name##Data* As##Name();
  HEAP_BROKER_OBJECT_LIST(DECLARE_IS_AND_AS)
#undef DECLARE_IS_AND_AS

69
  Handle<Object> object() const { return object_; }
70 71
  ObjectDataKind kind() const { return kind_; }
  bool is_smi() const { return kind_ == kSmi; }
72

73 74
 private:
  Handle<Object> const object_;
75
  ObjectDataKind const kind_;
76
};
77

78 79
class HeapObjectData : public ObjectData {
 public:
80 81
  HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
                 Handle<HeapObject> object);
82 83

  bool boolean_value() const { return boolean_value_; }
84
  MapData* map() const { return map_; }
85

86 87
  static HeapObjectData* Serialize(JSHeapBroker* broker,
                                   Handle<HeapObject> object);
88 89

 private:
90
  bool const boolean_value_;
91
  MapData* const map_;
92 93
};

94 95
class PropertyCellData : public HeapObjectData {
 public:
96 97
  PropertyCellData(JSHeapBroker* broker, ObjectData** storage,
                   Handle<PropertyCell> object);
98 99 100

  PropertyDetails property_details() const { return property_details_; }

101
  void Serialize(JSHeapBroker* broker);
102 103 104 105 106 107 108
  ObjectData* value() { return value_; }

 private:
  PropertyDetails const property_details_;

  bool serialized_ = false;
  ObjectData* value_ = nullptr;
109 110
};

111 112 113 114 115 116 117 118 119
void JSHeapBroker::IncrementTracingIndentation() { ++tracing_indentation_; }

void JSHeapBroker::DecrementTracingIndentation() { --tracing_indentation_; }

class TraceScope {
 public:
  TraceScope(JSHeapBroker* broker, const char* label)
      : TraceScope(broker, static_cast<void*>(broker), label) {}

120 121
  TraceScope(JSHeapBroker* broker, ObjectData* data, const char* label)
      : TraceScope(broker, static_cast<void*>(data), label) {}
122 123 124 125 126 127 128 129 130 131 132 133 134

  ~TraceScope() { broker_->DecrementTracingIndentation(); }

 private:
  JSHeapBroker* const broker_;

  TraceScope(JSHeapBroker* broker, void* self, const char* label)
      : broker_(broker) {
    broker_->Trace("Running %s on %p.\n", label, self);
    broker_->IncrementTracingIndentation();
  }
};

135
PropertyCellData::PropertyCellData(JSHeapBroker* broker, ObjectData** storage,
136
                                   Handle<PropertyCell> object)
137
    : HeapObjectData(broker, storage, object),
138 139
      property_details_(object->property_details()) {}

140
void PropertyCellData::Serialize(JSHeapBroker* broker) {
141 142 143
  if (serialized_) return;
  serialized_ = true;

144
  TraceScope tracer(broker, this, "PropertyCellData::Serialize");
145 146
  auto cell = Handle<PropertyCell>::cast(object());
  DCHECK_NULL(value_);
147
  value_ = broker->GetOrCreateData(cell->value());
148 149
}

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
class JSObjectField {
 public:
  bool IsDouble() const { return object_ == nullptr; }
  double AsDouble() const {
    CHECK(IsDouble());
    return number_;
  }

  bool IsObject() const { return object_ != nullptr; }
  ObjectData* AsObject() const {
    CHECK(IsObject());
    return object_;
  }

  explicit JSObjectField(double value) : number_(value) {}
  explicit JSObjectField(ObjectData* value) : object_(value) {}

 private:
  ObjectData* object_ = nullptr;
  double number_ = 0;
};

172 173
class JSObjectData : public HeapObjectData {
 public:
174 175
  JSObjectData(JSHeapBroker* broker, ObjectData** storage,
               Handle<JSObject> object);
176 177

  // Recursively serializes all reachable JSObjects.
178
  void SerializeAsBoilerplate(JSHeapBroker* broker);
179
  // Shallow serialization of {elements}.
180
  void SerializeElements(JSHeapBroker* broker);
181 182 183 184 185 186 187

  const JSObjectField& GetInobjectField(int property_index) const;
  FixedArrayBaseData* elements() const;

  // This method is only used to assert our invariants.
  bool cow_or_empty_elements_tenured() const;

188
  void SerializeObjectCreateMap(JSHeapBroker* broker);
189 190 191 192 193
  MapData* object_create_map() const {  // Can be nullptr.
    CHECK(serialized_object_create_map_);
    return object_create_map_;
  }

194
 private:
195
  void SerializeRecursive(JSHeapBroker* broker, int max_depths);
196 197 198

  FixedArrayBaseData* elements_ = nullptr;
  bool cow_or_empty_elements_tenured_ = false;
199
  // The {serialized_as_boilerplate} flag is set when all recursively
200
  // reachable JSObjects are serialized.
201 202
  bool serialized_as_boilerplate_ = false;
  bool serialized_elements_ = false;
203 204

  ZoneVector<JSObjectField> inobject_fields_;
205 206 207

  bool serialized_object_create_map_ = false;
  MapData* object_create_map_ = nullptr;
208 209
};

210
void JSObjectData::SerializeObjectCreateMap(JSHeapBroker* broker) {
211 212 213
  if (serialized_object_create_map_) return;
  serialized_object_create_map_ = true;

214
  TraceScope tracer(broker, this, "JSObjectData::SerializeObjectCreateMap");
215 216 217 218
  Handle<JSObject> jsobject = Handle<JSObject>::cast(object());

  if (jsobject->map()->is_prototype_map()) {
    Handle<Object> maybe_proto_info(jsobject->map()->prototype_info(),
219
                                    broker->isolate());
220 221 222 223 224
    if (maybe_proto_info->IsPrototypeInfo()) {
      auto proto_info = Handle<PrototypeInfo>::cast(maybe_proto_info);
      if (proto_info->HasObjectCreateMap()) {
        DCHECK_NULL(object_create_map_);
        object_create_map_ =
225
            broker->GetOrCreateData(proto_info->ObjectCreateMap())->AsMap();
226 227 228 229 230
      }
    }
  }
}

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
class JSTypedArrayData : public JSObjectData {
 public:
  JSTypedArrayData(JSHeapBroker* broker, ObjectData** storage,
                   Handle<JSTypedArray> object);

  bool is_on_heap() const { return is_on_heap_; }
  size_t length_value() const { return length_value_; }
  void* elements_external_pointer() const { return elements_external_pointer_; }

  void Serialize(JSHeapBroker* broker);

  HeapObjectData* buffer() const { return buffer_; }

 private:
  bool const is_on_heap_;
  size_t const length_value_;
  void* const elements_external_pointer_;

  bool serialized_ = false;
  HeapObjectData* buffer_ = nullptr;
};

JSTypedArrayData::JSTypedArrayData(JSHeapBroker* broker, ObjectData** storage,
                                   Handle<JSTypedArray> object)
    : JSObjectData(broker, storage, object),
      is_on_heap_(object->is_on_heap()),
      length_value_(object->length_value()),
      elements_external_pointer_(
          FixedTypedArrayBase::cast(object->elements())->external_pointer()) {}

void JSTypedArrayData::Serialize(JSHeapBroker* broker) {
  if (serialized_) return;
  serialized_ = true;

  TraceScope tracer(broker, this, "JSTypedArrayData::Serialize");
  Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object());

  if (!is_on_heap()) {
    DCHECK_NULL(buffer_);
    buffer_ = broker->GetOrCreateData(typed_array->buffer())->AsHeapObject();
  }
}

274 275
class JSFunctionData : public JSObjectData {
 public:
276 277
  JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
                 Handle<JSFunction> object);
278

279 280 281 282 283 284
  bool has_initial_map() const { return has_initial_map_; }
  bool has_prototype() const { return has_prototype_; }
  bool PrototypeRequiresRuntimeLookup() const {
    return PrototypeRequiresRuntimeLookup_;
  }

285
  void Serialize(JSHeapBroker* broker);
286

287
  NativeContextData* native_context() const { return native_context_; }
288 289 290
  MapData* initial_map() const { return initial_map_; }
  ObjectData* prototype() const { return prototype_; }
  SharedFunctionInfoData* shared() const { return shared_; }
291 292 293 294
  int initial_map_instance_size_with_min_slack() const {
    CHECK(serialized_);
    return initial_map_instance_size_with_min_slack_;
  }
295 296 297 298 299 300 301 302

 private:
  bool has_initial_map_;
  bool has_prototype_;
  bool PrototypeRequiresRuntimeLookup_;

  bool serialized_ = false;

303
  NativeContextData* native_context_ = nullptr;
304 305 306
  MapData* initial_map_ = nullptr;
  ObjectData* prototype_ = nullptr;
  SharedFunctionInfoData* shared_ = nullptr;
307
  int initial_map_instance_size_with_min_slack_;
308 309
};

310 311
class JSRegExpData : public JSObjectData {
 public:
312 313 314
  JSRegExpData(JSHeapBroker* broker, ObjectData** storage,
               Handle<JSRegExp> object)
      : JSObjectData(broker, storage, object) {}
315

316
  void SerializeAsRegExpBoilerplate(JSHeapBroker* broker);
317 318 319 320 321 322 323 324

  ObjectData* raw_properties_or_hash() const { return raw_properties_or_hash_; }
  ObjectData* data() const { return data_; }
  ObjectData* source() const { return source_; }
  ObjectData* flags() const { return flags_; }
  ObjectData* last_index() const { return last_index_; }

 private:
325
  bool serialized_as_reg_exp_boilerplate_ = false;
326 327 328 329 330 331

  ObjectData* raw_properties_or_hash_ = nullptr;
  ObjectData* data_ = nullptr;
  ObjectData* source_ = nullptr;
  ObjectData* flags_ = nullptr;
  ObjectData* last_index_ = nullptr;
332 333 334 335
};

class HeapNumberData : public HeapObjectData {
 public:
336 337 338
  HeapNumberData(JSHeapBroker* broker, ObjectData** storage,
                 Handle<HeapNumber> object)
      : HeapObjectData(broker, storage, object), value_(object->value()) {}
339 340 341 342 343

  double value() const { return value_; }

 private:
  double const value_;
344 345 346 347
};

class MutableHeapNumberData : public HeapObjectData {
 public:
348 349 350
  MutableHeapNumberData(JSHeapBroker* broker, ObjectData** storage,
                        Handle<MutableHeapNumber> object)
      : HeapObjectData(broker, storage, object), value_(object->value()) {}
351 352 353 354 355

  double value() const { return value_; }

 private:
  double const value_;
356
};
357

358 359
class ContextData : public HeapObjectData {
 public:
360 361
  ContextData(JSHeapBroker* broker, ObjectData** storage,
              Handle<Context> object);
362
  void Serialize(JSHeapBroker* broker);
363 364 365 366 367 368 369 370 371

  ContextData* previous() const {
    CHECK(serialized_);
    return previous_;
  }

 private:
  bool serialized_ = false;
  ContextData* previous_ = nullptr;
372
};
373

374 375 376
ContextData::ContextData(JSHeapBroker* broker, ObjectData** storage,
                         Handle<Context> object)
    : HeapObjectData(broker, storage, object) {}
377

378
void ContextData::Serialize(JSHeapBroker* broker) {
379 380 381
  if (serialized_) return;
  serialized_ = true;

382
  TraceScope tracer(broker, this, "ContextData::Serialize");
383 384 385 386 387
  Handle<Context> context = Handle<Context>::cast(object());

  DCHECK_NULL(previous_);
  // Context::previous DCHECK-fails when called on the native context.
  if (!context->IsNativeContext()) {
388 389
    previous_ = broker->GetOrCreateData(context->previous())->AsContext();
    previous_->Serialize(broker);
390 391 392
  }
}

393 394
class NativeContextData : public ContextData {
 public:
395 396 397 398
#define DECL_ACCESSOR(type, name) \
  type##Data* name() const { return name##_; }
  BROKER_NATIVE_CONTEXT_FIELDS(DECL_ACCESSOR)
#undef DECL_ACCESSOR
399

400 401 402 403 404
  const ZoneVector<MapData*>& function_maps() const {
    CHECK(serialized_);
    return function_maps_;
  }

405 406
  NativeContextData(JSHeapBroker* broker, ObjectData** storage,
                    Handle<NativeContext> object);
407
  void Serialize(JSHeapBroker* broker);
408 409 410 411 412 413

 private:
  bool serialized_ = false;
#define DECL_MEMBER(type, name) type##Data* name##_ = nullptr;
  BROKER_NATIVE_CONTEXT_FIELDS(DECL_MEMBER)
#undef DECL_MEMBER
414
  ZoneVector<MapData*> function_maps_;
415 416
};

417 418
class NameData : public HeapObjectData {
 public:
419 420
  NameData(JSHeapBroker* broker, ObjectData** storage, Handle<Name> object)
      : HeapObjectData(broker, storage, object) {}
421 422 423 424
};

class StringData : public NameData {
 public:
425
  StringData(JSHeapBroker* broker, ObjectData** storage, Handle<String> object);
426

427 428 429
  int length() const { return length_; }
  uint16_t first_char() const { return first_char_; }
  base::Optional<double> to_number() const { return to_number_; }
430 431
  bool is_external_string() const { return is_external_string_; }
  bool is_seq_string() const { return is_seq_string_; }
432

433
 private:
434 435 436
  int const length_;
  uint16_t const first_char_;
  base::Optional<double> to_number_;
437 438
  bool const is_external_string_;
  bool const is_seq_string_;
439

440
  static constexpr int kMaxLengthForDoubleConversion = 23;
441 442
};

443 444 445
StringData::StringData(JSHeapBroker* broker, ObjectData** storage,
                       Handle<String> object)
    : NameData(broker, storage, object),
446 447 448 449 450 451 452 453 454 455 456
      length_(object->length()),
      first_char_(length_ > 0 ? object->Get(0) : 0),
      is_external_string_(object->IsExternalString()),
      is_seq_string_(object->IsSeqString()) {
  int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
  if (length_ <= kMaxLengthForDoubleConversion) {
    to_number_ = StringToDouble(
        broker->isolate(), broker->isolate()->unicode_cache(), object, flags);
  }
}

457 458
class InternalizedStringData : public StringData {
 public:
459
  InternalizedStringData(JSHeapBroker* broker, ObjectData** storage,
460
                         Handle<InternalizedString> object)
461
      : StringData(broker, storage, object) {}
462 463
};

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
namespace {

bool IsFastLiteralHelper(Handle<JSObject> boilerplate, int max_depth,
                         int* max_properties) {
  DCHECK_GE(max_depth, 0);
  DCHECK_GE(*max_properties, 0);

  // Make sure the boilerplate map is not deprecated.
  if (!JSObject::TryMigrateInstance(boilerplate)) return false;

  // Check for too deep nesting.
  if (max_depth == 0) return false;

  // Check the elements.
  Isolate* const isolate = boilerplate->GetIsolate();
  Handle<FixedArrayBase> elements(boilerplate->elements(), isolate);
  if (elements->length() > 0 &&
      elements->map() != ReadOnlyRoots(isolate).fixed_cow_array_map()) {
    if (boilerplate->HasSmiOrObjectElements()) {
      Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
      int length = elements->length();
      for (int i = 0; i < length; i++) {
        if ((*max_properties)-- == 0) return false;
        Handle<Object> value(fast_elements->get(i), isolate);
        if (value->IsJSObject()) {
          Handle<JSObject> value_object = Handle<JSObject>::cast(value);
          if (!IsFastLiteralHelper(value_object, max_depth - 1,
                                   max_properties)) {
            return false;
          }
        }
      }
    } else if (boilerplate->HasDoubleElements()) {
      if (elements->Size() > kMaxRegularHeapObjectSize) return false;
    } else {
      return false;
    }
  }

  // TODO(turbofan): Do we want to support out-of-object properties?
  if (!(boilerplate->HasFastProperties() &&
        boilerplate->property_array()->length() == 0)) {
    return false;
  }

  // Check the in-object properties.
  Handle<DescriptorArray> descriptors(
      boilerplate->map()->instance_descriptors(), isolate);
  int limit = boilerplate->map()->NumberOfOwnDescriptors();
  for (int i = 0; i < limit; i++) {
    PropertyDetails details = descriptors->GetDetails(i);
    if (details.location() != kField) continue;
    DCHECK_EQ(kData, details.kind());
    if ((*max_properties)-- == 0) return false;
    FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
    if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
    Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), isolate);
    if (value->IsJSObject()) {
      Handle<JSObject> value_object = Handle<JSObject>::cast(value);
      if (!IsFastLiteralHelper(value_object, max_depth - 1, max_properties)) {
        return false;
      }
    }
  }
  return true;
}

// Maximum depth and total number of elements and properties for literal
// graphs to be considered for fast deep-copying. The limit is chosen to
// match the maximum number of inobject properties, to ensure that the
// performance of using object literals is not worse than using constructor
// functions, see crbug.com/v8/6211 for details.
const int kMaxFastLiteralDepth = 3;
const int kMaxFastLiteralProperties = JSObject::kMaxInObjectProperties;

// Determines whether the given array or object literal boilerplate satisfies
// all limits to be considered for fast deep-copying and computes the total
// size of all objects that are part of the graph.
bool IsInlinableFastLiteral(Handle<JSObject> boilerplate) {
  int max_properties = kMaxFastLiteralProperties;
  return IsFastLiteralHelper(boilerplate, kMaxFastLiteralDepth,
                             &max_properties);
}

}  // namespace

class AllocationSiteData : public HeapObjectData {
 public:
552 553
  AllocationSiteData(JSHeapBroker* broker, ObjectData** storage,
                     Handle<AllocationSite> object);
554
  void SerializeBoilerplate(JSHeapBroker* broker);
555

556 557 558 559 560
  bool PointsToLiteral() const { return PointsToLiteral_; }
  PretenureFlag GetPretenureMode() const { return GetPretenureMode_; }
  ObjectData* nested_site() const { return nested_site_; }
  bool IsFastLiteral() const { return IsFastLiteral_; }
  JSObjectData* boilerplate() const { return boilerplate_; }
561 562

  // These are only valid if PointsToLiteral is false.
563 564 565 566 567 568 569 570 571 572 573
  ElementsKind GetElementsKind() const { return GetElementsKind_; }
  bool CanInlineCall() const { return CanInlineCall_; }

 private:
  bool const PointsToLiteral_;
  PretenureFlag const GetPretenureMode_;
  ObjectData* nested_site_ = nullptr;
  bool IsFastLiteral_ = false;
  JSObjectData* boilerplate_ = nullptr;
  ElementsKind GetElementsKind_ = NO_ELEMENTS;
  bool CanInlineCall_ = false;
574
  bool serialized_boilerplate_ = false;
575 576
};

577 578 579
// Only used in JSNativeContextSpecialization.
class ScriptContextTableData : public HeapObjectData {
 public:
580
  ScriptContextTableData(JSHeapBroker* broker, ObjectData** storage,
581
                         Handle<ScriptContextTable> object)
582
      : HeapObjectData(broker, storage, object) {}
583
};
584

585 586 587 588 589 590
struct PropertyDescriptor {
  NameData* key = nullptr;
  PropertyDetails details = PropertyDetails::Empty();
  FieldIndex field_index;
  MapData* field_owner = nullptr;
  ObjectData* field_type = nullptr;
591
  bool is_unboxed_double_field = false;
592 593
};

594 595
class MapData : public HeapObjectData {
 public:
596
  MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object);
597

598 599 600 601 602
  InstanceType instance_type() const { return instance_type_; }
  int instance_size() const { return instance_size_; }
  byte bit_field() const { return bit_field_; }
  byte bit_field2() const { return bit_field2_; }
  uint32_t bit_field3() const { return bit_field3_; }
603 604 605 606 607 608 609 610 611 612
  bool can_be_deprecated() const { return can_be_deprecated_; }
  bool can_transition() const { return can_transition_; }
  int in_object_properties_start_in_words() const {
    CHECK(InstanceTypeChecker::IsJSObject(instance_type()));
    return in_object_properties_start_in_words_;
  }
  int in_object_properties() const {
    CHECK(InstanceTypeChecker::IsJSObject(instance_type()));
    return in_object_properties_;
  }
613
  int constructor_function_index() const { return constructor_function_index_; }
614 615

  // Extra information.
616

617
  void SerializeElementsKindGeneralizations(JSHeapBroker* broker);
618 619
  const ZoneVector<MapData*>& elements_kind_generalizations() const {
    CHECK(serialized_elements_kind_generalizations_);
620 621 622
    return elements_kind_generalizations_;
  }

623 624
  // Serialize the own part of the descriptor array and, recursively, that of
  // any field owner.
625
  void SerializeOwnDescriptors(JSHeapBroker* broker);
626 627 628
  DescriptorArrayData* instance_descriptors() const {
    CHECK(serialized_own_descriptors_);
    return instance_descriptors_;
629 630
  }

631 632 633 634
  void SerializeConstructor(JSHeapBroker* broker);
  ObjectData* GetConstructor() const {
    CHECK(serialized_constructor_);
    return constructor_;
635 636
  }

637
  void SerializePrototype(JSHeapBroker* broker);
638 639 640 641 642
  ObjectData* prototype() const {
    CHECK(serialized_prototype_);
    return prototype_;
  }

643
 private:
644 645 646 647 648
  InstanceType const instance_type_;
  int const instance_size_;
  byte const bit_field_;
  byte const bit_field2_;
  uint32_t const bit_field3_;
649 650 651 652
  bool const can_be_deprecated_;
  bool const can_transition_;
  int const in_object_properties_start_in_words_;
  int const in_object_properties_;
653
  int const constructor_function_index_;
654

655
  bool serialized_elements_kind_generalizations_ = false;
656
  ZoneVector<MapData*> elements_kind_generalizations_;
657

658 659
  bool serialized_own_descriptors_ = false;
  DescriptorArrayData* instance_descriptors_ = nullptr;
660

661 662
  bool serialized_constructor_ = false;
  ObjectData* constructor_ = nullptr;
663

664 665
  bool serialized_prototype_ = false;
  ObjectData* prototype_ = nullptr;
666 667
};

668
AllocationSiteData::AllocationSiteData(JSHeapBroker* broker,
669
                                       ObjectData** storage,
670
                                       Handle<AllocationSite> object)
671
    : HeapObjectData(broker, storage, object),
672 673 674 675 676 677 678 679 680 681 682
      PointsToLiteral_(object->PointsToLiteral()),
      GetPretenureMode_(object->GetPretenureMode()) {
  if (PointsToLiteral_) {
    IsFastLiteral_ = IsInlinableFastLiteral(
        handle(object->boilerplate(), broker->isolate()));
  } else {
    GetElementsKind_ = object->GetElementsKind();
    CanInlineCall_ = object->CanInlineCall();
  }
}

683
void AllocationSiteData::SerializeBoilerplate(JSHeapBroker* broker) {
684 685 686
  if (serialized_boilerplate_) return;
  serialized_boilerplate_ = true;

687
  TraceScope tracer(broker, this, "AllocationSiteData::SerializeBoilerplate");
688 689 690 691
  Handle<AllocationSite> site = Handle<AllocationSite>::cast(object());

  CHECK(IsFastLiteral_);
  DCHECK_NULL(boilerplate_);
692 693
  boilerplate_ = broker->GetOrCreateData(site->boilerplate())->AsJSObject();
  boilerplate_->SerializeAsBoilerplate(broker);
694 695

  DCHECK_NULL(nested_site_);
696
  nested_site_ = broker->GetOrCreateData(site->nested_site());
697
  if (nested_site_->IsAllocationSite()) {
698
    nested_site_->AsAllocationSite()->SerializeBoilerplate(broker);
699 700 701
  }
}

702 703
HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
                               Handle<HeapObject> object)
704
    : ObjectData(broker, storage, object, kSerializedHeapObject),
705
      boolean_value_(object->BooleanValue(broker->isolate())),
706 707 708 709 710 711
      // We have to use a raw cast below instead of AsMap() because of
      // recursion. AsMap() would call IsMap(), which accesses the
      // instance_type_ member. In the case of constructing the MapData for the
      // meta map (whose map is itself), this member has not yet been
      // initialized.
      map_(static_cast<MapData*>(broker->GetOrCreateData(object->map()))) {
712 713 714
  CHECK(broker->SerializingAllowed());
}

715 716
MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object)
    : HeapObjectData(broker, storage, object),
717 718 719 720 721
      instance_type_(object->instance_type()),
      instance_size_(object->instance_size()),
      bit_field_(object->bit_field()),
      bit_field2_(object->bit_field2()),
      bit_field3_(object->bit_field3()),
722 723 724 725 726 727 728 729 730
      can_be_deprecated_(object->NumberOfOwnDescriptors() > 0
                             ? object->CanBeDeprecated()
                             : false),
      can_transition_(object->CanTransition()),
      in_object_properties_start_in_words_(
          object->IsJSObjectMap() ? object->GetInObjectPropertiesStartInWords()
                                  : 0),
      in_object_properties_(
          object->IsJSObjectMap() ? object->GetInObjectProperties() : 0),
731 732 733
      constructor_function_index_(object->IsPrimitiveMap()
                                      ? object->GetConstructorFunctionIndex()
                                      : Map::kNoConstructorFunctionIndex),
734
      elements_kind_generalizations_(broker->zone()) {}
735

736 737 738
JSFunctionData::JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
                               Handle<JSFunction> object)
    : JSObjectData(broker, storage, object),
739 740 741
      has_initial_map_(object->has_prototype_slot() &&
                       object->has_initial_map()),
      has_prototype_(object->has_prototype_slot() && object->has_prototype()),
742
      PrototypeRequiresRuntimeLookup_(
743
          object->PrototypeRequiresRuntimeLookup()) {}
744

745
void JSFunctionData::Serialize(JSHeapBroker* broker) {
746 747 748
  if (serialized_) return;
  serialized_ = true;

749
  TraceScope tracer(broker, this, "JSFunctionData::Serialize");
750
  Handle<JSFunction> function = Handle<JSFunction>::cast(object());
751

752
  DCHECK_NULL(native_context_);
753 754 755
  DCHECK_NULL(initial_map_);
  DCHECK_NULL(prototype_);
  DCHECK_NULL(shared_);
756

757 758
  native_context_ =
      broker->GetOrCreateData(function->native_context())->AsNativeContext();
759 760 761 762 763 764
  shared_ = broker->GetOrCreateData(function->shared())->AsSharedFunctionInfo();
  initial_map_ = has_initial_map()
                     ? broker->GetOrCreateData(function->initial_map())->AsMap()
                     : nullptr;
  prototype_ = has_prototype() ? broker->GetOrCreateData(function->prototype())
                               : nullptr;
765

766
  if (initial_map_ != nullptr) {
767
    initial_map_instance_size_with_min_slack_ =
768
        function->ComputeInstanceSizeWithMinSlack(broker->isolate());
769
    if (initial_map_->instance_type() == JS_ARRAY_TYPE) {
770
      initial_map_->SerializeElementsKindGeneralizations(broker);
771
    }
772
    initial_map_->SerializeConstructor(broker);
773 774 775
    // TODO(neis): This is currently only needed for native_context's
    // object_function, as used by GetObjectCreateMap. If no further use sites
    // show up, we should move this into NativeContextData::Serialize.
776
    initial_map_->SerializePrototype(broker);
777 778 779
  }
}

780
void MapData::SerializeElementsKindGeneralizations(JSHeapBroker* broker) {
781 782 783
  if (serialized_elements_kind_generalizations_) return;
  serialized_elements_kind_generalizations_ = true;

784 785
  TraceScope tracer(broker, this,
                    "MapData::SerializeElementsKindGeneralizations");
786
  DCHECK_EQ(instance_type(), JS_ARRAY_TYPE);
787
  MapRef self(broker, this);
788
  ElementsKind from_kind = self.elements_kind();
789
  DCHECK(elements_kind_generalizations_.empty());
790 791 792 793
  for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
    ElementsKind to_kind = static_cast<ElementsKind>(i);
    if (IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
      Handle<Map> target =
794
          Map::AsElementsKind(broker->isolate(), self.object(), to_kind);
795
      elements_kind_generalizations_.push_back(
796
          broker->GetOrCreateData(target)->AsMap());
797 798 799 800
    }
  }
}

801 802 803 804 805 806 807 808 809 810 811 812
class DescriptorArrayData : public HeapObjectData {
 public:
  DescriptorArrayData(JSHeapBroker* broker, ObjectData** storage,
                      Handle<DescriptorArray> object)
      : HeapObjectData(broker, storage, object), contents_(broker->zone()) {}

  ZoneVector<PropertyDescriptor>& contents() { return contents_; }

 private:
  ZoneVector<PropertyDescriptor> contents_;
};

813 814 815 816
class FeedbackVectorData : public HeapObjectData {
 public:
  const ZoneVector<ObjectData*>& feedback() { return feedback_; }

817 818
  FeedbackVectorData(JSHeapBroker* broker, ObjectData** storage,
                     Handle<FeedbackVector> object);
819

820
  void SerializeSlots(JSHeapBroker* broker);
821

822
 private:
823
  bool serialized_ = false;
824 825 826
  ZoneVector<ObjectData*> feedback_;
};

827
FeedbackVectorData::FeedbackVectorData(JSHeapBroker* broker,
828
                                       ObjectData** storage,
829
                                       Handle<FeedbackVector> object)
830
    : HeapObjectData(broker, storage, object), feedback_(broker->zone()) {}
831

832
void FeedbackVectorData::SerializeSlots(JSHeapBroker* broker) {
833 834
  if (serialized_) return;
  serialized_ = true;
835

836
  TraceScope tracer(broker, this, "FeedbackVectorData::SerializeSlots");
837
  Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(object());
838
  DCHECK(feedback_.empty());
839 840 841
  feedback_.reserve(vector->length());
  for (int i = 0; i < vector->length(); ++i) {
    MaybeObject* value = vector->get(i);
842
    ObjectData* slot_value =
843
        value->IsObject() ? broker->GetOrCreateData(value->cast<Object>())
844
                          : nullptr;
845 846 847
    feedback_.push_back(slot_value);
    if (slot_value == nullptr) continue;

848 849
    if (slot_value->IsAllocationSite() &&
        slot_value->AsAllocationSite()->IsFastLiteral()) {
850
      slot_value->AsAllocationSite()->SerializeBoilerplate(broker);
851
    } else if (slot_value->IsJSRegExp()) {
852
      slot_value->AsJSRegExp()->SerializeAsRegExpBoilerplate(broker);
853
    }
854
  }
855
  DCHECK_EQ(vector->length(), feedback_.size());
856
  broker->Trace("Copied %zu slots.\n", feedback_.size());
857 858
}

859 860
class FixedArrayBaseData : public HeapObjectData {
 public:
861 862 863
  FixedArrayBaseData(JSHeapBroker* broker, ObjectData** storage,
                     Handle<FixedArrayBase> object)
      : HeapObjectData(broker, storage, object), length_(object->length()) {}
864 865 866 867 868

  int length() const { return length_; }

 private:
  int const length_;
869 870
};

871 872 873 874
JSObjectData::JSObjectData(JSHeapBroker* broker, ObjectData** storage,
                           Handle<JSObject> object)
    : HeapObjectData(broker, storage, object),
      inobject_fields_(broker->zone()) {}
875

876 877
class FixedArrayData : public FixedArrayBaseData {
 public:
878 879
  FixedArrayData(JSHeapBroker* broker, ObjectData** storage,
                 Handle<FixedArray> object);
880 881

  // Creates all elements of the fixed array.
882
  void SerializeContents(JSHeapBroker* broker);
883 884 885 886

  ObjectData* Get(int i) const;

 private:
887
  bool serialized_contents_ = false;
888
  ZoneVector<ObjectData*> contents_;
889 890
};

891
void FixedArrayData::SerializeContents(JSHeapBroker* broker) {
892 893
  if (serialized_contents_) return;
  serialized_contents_ = true;
894

895
  TraceScope tracer(broker, this, "FixedArrayData::SerializeContents");
896 897
  Handle<FixedArray> array = Handle<FixedArray>::cast(object());
  CHECK_EQ(array->length(), length());
898 899 900 901
  CHECK(contents_.empty());
  contents_.reserve(static_cast<size_t>(length()));

  for (int i = 0; i < length(); i++) {
902 903
    Handle<Object> value(array->get(i), broker->isolate());
    contents_.push_back(broker->GetOrCreateData(value));
904
  }
905
  broker->Trace("Copied %zu elements.\n", contents_.size());
906 907
}

908 909 910
FixedArrayData::FixedArrayData(JSHeapBroker* broker, ObjectData** storage,
                               Handle<FixedArray> object)
    : FixedArrayBaseData(broker, storage, object), contents_(broker->zone()) {}
911

912 913
class FixedDoubleArrayData : public FixedArrayBaseData {
 public:
914 915
  FixedDoubleArrayData(JSHeapBroker* broker, ObjectData** storage,
                       Handle<FixedDoubleArray> object);
916 917

  // Serializes all elements of the fixed array.
918
  void SerializeContents(JSHeapBroker* broker);
919 920 921 922

  Float64 Get(int i) const;

 private:
923
  bool serialized_contents_ = false;
924
  ZoneVector<Float64> contents_;
925
};
926

927
FixedDoubleArrayData::FixedDoubleArrayData(JSHeapBroker* broker,
928
                                           ObjectData** storage,
929
                                           Handle<FixedDoubleArray> object)
930
    : FixedArrayBaseData(broker, storage, object), contents_(broker->zone()) {}
931

932
void FixedDoubleArrayData::SerializeContents(JSHeapBroker* broker) {
933 934
  if (serialized_contents_) return;
  serialized_contents_ = true;
935

936
  TraceScope tracer(broker, this, "FixedDoubleArrayData::SerializeContents");
937 938
  Handle<FixedDoubleArray> self = Handle<FixedDoubleArray>::cast(object());
  CHECK_EQ(self->length(), length());
939 940 941 942
  CHECK(contents_.empty());
  contents_.reserve(static_cast<size_t>(length()));

  for (int i = 0; i < length(); i++) {
943
    contents_.push_back(Float64::FromBits(self->get_representation(i)));
944
  }
945
  broker->Trace("Copied %zu elements.\n", contents_.size());
946 947
}

948 949
class BytecodeArrayData : public FixedArrayBaseData {
 public:
950
  int register_count() const { return register_count_; }
951

952 953 954
  BytecodeArrayData(JSHeapBroker* broker, ObjectData** storage,
                    Handle<BytecodeArray> object)
      : FixedArrayBaseData(broker, storage, object),
955 956 957 958
        register_count_(object->register_count()) {}

 private:
  int const register_count_;
959 960
};

961 962
class JSArrayData : public JSObjectData {
 public:
963 964
  JSArrayData(JSHeapBroker* broker, ObjectData** storage,
              Handle<JSArray> object);
965
  void Serialize(JSHeapBroker* broker);
966 967 968 969 970 971

  ObjectData* length() const { return length_; }

 private:
  bool serialized_ = false;
  ObjectData* length_ = nullptr;
972 973
};

974 975 976
JSArrayData::JSArrayData(JSHeapBroker* broker, ObjectData** storage,
                         Handle<JSArray> object)
    : JSObjectData(broker, storage, object) {}
977

978
void JSArrayData::Serialize(JSHeapBroker* broker) {
979 980 981
  if (serialized_) return;
  serialized_ = true;

982
  TraceScope tracer(broker, this, "JSArrayData::Serialize");
983 984
  Handle<JSArray> jsarray = Handle<JSArray>::cast(object());
  DCHECK_NULL(length_);
985
  length_ = broker->GetOrCreateData(jsarray->length());
986 987
}

988 989
class ScopeInfoData : public HeapObjectData {
 public:
990 991
  ScopeInfoData(JSHeapBroker* broker, ObjectData** storage,
                Handle<ScopeInfo> object);
992 993 994 995 996

  int context_length() const { return context_length_; }

 private:
  int const context_length_;
997
};
998

999 1000 1001
ScopeInfoData::ScopeInfoData(JSHeapBroker* broker, ObjectData** storage,
                             Handle<ScopeInfo> object)
    : HeapObjectData(broker, storage, object),
1002 1003
      context_length_(object->ContextLength()) {}

1004 1005
class SharedFunctionInfoData : public HeapObjectData {
 public:
1006 1007 1008 1009 1010 1011
  int builtin_id() const { return builtin_id_; }
  BytecodeArrayData* GetBytecodeArray() const { return GetBytecodeArray_; }
#define DECL_ACCESSOR(type, name) \
  type name() const { return name##_; }
  BROKER_SFI_FIELDS(DECL_ACCESSOR)
#undef DECL_ACCESSOR
1012

1013
  SharedFunctionInfoData(JSHeapBroker* broker, ObjectData** storage,
1014
                         Handle<SharedFunctionInfo> object)
1015
      : HeapObjectData(broker, storage, object),
1016
        builtin_id_(object->HasBuiltinId() ? object->builtin_id()
1017
                                           : Builtins::kNoBuiltinId),
1018 1019 1020 1021
        GetBytecodeArray_(
            object->HasBytecodeArray()
                ? broker->GetOrCreateData(object->GetBytecodeArray())
                      ->AsBytecodeArray()
1022
                : nullptr)
1023
#define INIT_MEMBER(type, name) , name##_(object->name())
1024 1025 1026
            BROKER_SFI_FIELDS(INIT_MEMBER)
#undef INIT_MEMBER
  {
1027 1028
    DCHECK_EQ(HasBuiltinId_, builtin_id_ != Builtins::kNoBuiltinId);
    DCHECK_EQ(HasBytecodeArray_, GetBytecodeArray_ != nullptr);
1029
  }
1030 1031 1032 1033 1034 1035 1036

 private:
  int const builtin_id_;
  BytecodeArrayData* const GetBytecodeArray_;
#define DECL_MEMBER(type, name) type const name##_;
  BROKER_SFI_FIELDS(DECL_MEMBER)
#undef DECL_MEMBER
1037 1038
};

1039 1040
class ModuleData : public HeapObjectData {
 public:
1041
  ModuleData(JSHeapBroker* broker, ObjectData** storage, Handle<Module> object);
1042
  void Serialize(JSHeapBroker* broker);
1043 1044 1045 1046 1047 1048 1049

  CellData* GetCell(int cell_index) const;

 private:
  bool serialized_ = false;
  ZoneVector<CellData*> imports_;
  ZoneVector<CellData*> exports_;
1050 1051
};

1052 1053 1054
ModuleData::ModuleData(JSHeapBroker* broker, ObjectData** storage,
                       Handle<Module> object)
    : HeapObjectData(broker, storage, object),
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
      imports_(broker->zone()),
      exports_(broker->zone()) {}

CellData* ModuleData::GetCell(int cell_index) const {
  CHECK(serialized_);
  CellData* cell;
  switch (ModuleDescriptor::GetCellIndexKind(cell_index)) {
    case ModuleDescriptor::kImport:
      cell = imports_.at(Module::ImportIndex(cell_index));
      break;
    case ModuleDescriptor::kExport:
      cell = exports_.at(Module::ExportIndex(cell_index));
      break;
    case ModuleDescriptor::kInvalid:
      UNREACHABLE();
      break;
  }
  CHECK_NOT_NULL(cell);
  return cell;
}
1075

1076
void ModuleData::Serialize(JSHeapBroker* broker) {
1077 1078 1079
  if (serialized_) return;
  serialized_ = true;

1080
  TraceScope tracer(broker, this, "ModuleData::Serialize");
1081 1082 1083 1084 1085 1086
  Handle<Module> module = Handle<Module>::cast(object());

  // TODO(neis): We could be smarter and only serialize the cells we care about.
  // TODO(neis): Define a helper for serializing a FixedArray into a ZoneVector.

  DCHECK(imports_.empty());
1087
  Handle<FixedArray> imports(module->regular_imports(), broker->isolate());
1088 1089 1090
  int const imports_length = imports->length();
  imports_.reserve(imports_length);
  for (int i = 0; i < imports_length; ++i) {
1091
    imports_.push_back(broker->GetOrCreateData(imports->get(i))->AsCell());
1092
  }
1093
  broker->Trace("Copied %zu imports.\n", imports_.size());
1094 1095

  DCHECK(exports_.empty());
1096
  Handle<FixedArray> exports(module->regular_exports(), broker->isolate());
1097 1098 1099
  int const exports_length = exports->length();
  exports_.reserve(exports_length);
  for (int i = 0; i < exports_length; ++i) {
1100
    exports_.push_back(broker->GetOrCreateData(exports->get(i))->AsCell());
1101
  }
1102
  broker->Trace("Copied %zu exports.\n", exports_.size());
1103 1104
}

1105 1106
class CellData : public HeapObjectData {
 public:
1107 1108 1109 1110 1111 1112 1113 1114
  CellData(JSHeapBroker* broker, ObjectData** storage, Handle<Cell> object);

  void Serialize(JSHeapBroker* broker);
  ObjectData* value() { return value_; }

 private:
  bool serialized_ = false;
  ObjectData* value_ = nullptr;
1115 1116
};

1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
CellData::CellData(JSHeapBroker* broker, ObjectData** storage,
                   Handle<Cell> object)
    : HeapObjectData(broker, storage, object) {}

void CellData::Serialize(JSHeapBroker* broker) {
  if (serialized_) return;
  serialized_ = true;

  TraceScope tracer(broker, this, "CellData::Serialize");
  auto cell = Handle<Cell>::cast(object());
  DCHECK_NULL(value_);
  value_ = broker->GetOrCreateData(cell->value());
}

1131 1132
class JSGlobalProxyData : public JSObjectData {
 public:
1133 1134 1135
  JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage,
                    Handle<JSGlobalProxy> object)
      : JSObjectData(broker, storage, object) {}
1136 1137 1138 1139
};

class CodeData : public HeapObjectData {
 public:
1140 1141
  CodeData(JSHeapBroker* broker, ObjectData** storage, Handle<Code> object)
      : HeapObjectData(broker, storage, object) {}
1142
};
1143

1144 1145
#define DEFINE_IS_AND_AS(Name)                                            \
  bool ObjectData::Is##Name() const {                                     \
1146
    if (kind() == kUnserializedHeapObject) {                              \
1147 1148 1149 1150 1151
      AllowHandleDereference allow_handle_dereference;                    \
      return object()->Is##Name();                                        \
    }                                                                     \
    if (is_smi()) return false;                                           \
    InstanceType instance_type =                                          \
1152
        static_cast<const HeapObjectData*>(this)->map()->instance_type(); \
1153 1154 1155
    return InstanceTypeChecker::Is##Name(instance_type);                  \
  }                                                                       \
  Name##Data* ObjectData::As##Name() {                                    \
1156
    CHECK_EQ(kind(), kSerializedHeapObject);                              \
1157 1158
    CHECK(Is##Name());                                                    \
    return static_cast<Name##Data*>(this);                                \
1159 1160 1161 1162
  }
HEAP_BROKER_OBJECT_LIST(DEFINE_IS_AND_AS)
#undef DEFINE_IS_AND_AS

1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
const JSObjectField& JSObjectData::GetInobjectField(int property_index) const {
  CHECK_LT(static_cast<size_t>(property_index), inobject_fields_.size());
  return inobject_fields_[property_index];
}

bool JSObjectData::cow_or_empty_elements_tenured() const {
  return cow_or_empty_elements_tenured_;
}

FixedArrayBaseData* JSObjectData::elements() const { return elements_; }

1174 1175
void JSObjectData::SerializeAsBoilerplate(JSHeapBroker* broker) {
  SerializeRecursive(broker, kMaxFastLiteralDepth);
1176 1177
}

1178
void JSObjectData::SerializeElements(JSHeapBroker* broker) {
1179 1180
  if (serialized_elements_) return;
  serialized_elements_ = true;
1181

1182
  TraceScope tracer(broker, this, "JSObjectData::SerializeElements");
1183
  Handle<JSObject> boilerplate = Handle<JSObject>::cast(object());
1184
  Handle<FixedArrayBase> elements_object(boilerplate->elements(),
1185
                                         broker->isolate());
1186
  DCHECK_NULL(elements_);
1187
  elements_ = broker->GetOrCreateData(elements_object)->AsFixedArrayBase();
1188 1189
}

1190 1191 1192
void MapData::SerializeConstructor(JSHeapBroker* broker) {
  if (serialized_constructor_) return;
  serialized_constructor_ = true;
1193

1194
  TraceScope tracer(broker, this, "MapData::SerializeConstructor");
1195
  Handle<Map> map = Handle<Map>::cast(object());
1196 1197
  DCHECK_NULL(constructor_);
  constructor_ = broker->GetOrCreateData(map->GetConstructor());
1198 1199
}

1200
void MapData::SerializePrototype(JSHeapBroker* broker) {
1201 1202 1203
  if (serialized_prototype_) return;
  serialized_prototype_ = true;

1204
  TraceScope tracer(broker, this, "MapData::SerializePrototype");
1205 1206
  Handle<Map> map = Handle<Map>::cast(object());
  DCHECK_NULL(prototype_);
1207
  prototype_ = broker->GetOrCreateData(map->prototype());
1208 1209
}

1210
void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) {
1211 1212
  if (serialized_own_descriptors_) return;
  serialized_own_descriptors_ = true;
1213

1214
  TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptors");
1215
  Handle<Map> map = Handle<Map>::cast(object());
1216 1217

  DCHECK_NULL(instance_descriptors_);
1218 1219
  instance_descriptors_ =
      broker->GetOrCreateData(map->instance_descriptors())->AsDescriptorArray();
1220 1221 1222 1223 1224 1225

  int const number_of_own = map->NumberOfOwnDescriptors();
  ZoneVector<PropertyDescriptor>& contents = instance_descriptors_->contents();
  int const current_size = static_cast<int>(contents.size());
  if (number_of_own <= current_size) return;

1226
  Isolate* const isolate = broker->isolate();
1227 1228 1229 1230 1231 1232 1233
  auto descriptors =
      Handle<DescriptorArray>::cast(instance_descriptors_->object());
  CHECK_EQ(*descriptors, map->instance_descriptors());
  contents.reserve(number_of_own);

  // Copy the new descriptors.
  for (int i = current_size; i < number_of_own; ++i) {
1234
    PropertyDescriptor d;
1235
    d.key = broker->GetOrCreateData(descriptors->GetKey(i))->AsName();
1236 1237 1238 1239
    d.details = descriptors->GetDetails(i);
    if (d.details.location() == kField) {
      d.field_index = FieldIndex::ForDescriptor(*map, i);
      d.field_owner =
1240 1241
          broker->GetOrCreateData(map->FindFieldOwner(isolate, i))->AsMap();
      d.field_type = broker->GetOrCreateData(descriptors->GetFieldType(i));
1242 1243
      d.is_unboxed_double_field = map->IsUnboxedDoubleField(d.field_index);
      // Recurse.
1244
    }
1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
    contents.push_back(d);
  }
  CHECK_EQ(number_of_own, contents.size());

  // Recurse on the new owner maps.
  for (int i = current_size; i < number_of_own; ++i) {
    const PropertyDescriptor& d = contents[i];
    if (d.details.location() == kField) {
      CHECK_LE(
          Handle<Map>::cast(d.field_owner->object())->NumberOfOwnDescriptors(),
          number_of_own);
1256
      d.field_owner->SerializeOwnDescriptors(broker);
1257
    }
1258
  }
1259

1260 1261 1262
  broker->Trace("Copied %zu descriptors into %p (%zu total).\n",
                number_of_own - current_size, instance_descriptors_,
                number_of_own);
1263 1264
}

1265
void JSObjectData::SerializeRecursive(JSHeapBroker* broker, int depth) {
1266 1267 1268
  if (serialized_as_boilerplate_) return;
  serialized_as_boilerplate_ = true;

1269
  TraceScope tracer(broker, this, "JSObjectData::SerializeRecursive");
1270
  Handle<JSObject> boilerplate = Handle<JSObject>::cast(object());
1271 1272 1273 1274 1275 1276 1277

  // We only serialize boilerplates that pass the IsInlinableFastLiteral
  // check, so we only do a sanity check on the depth here.
  CHECK_GT(depth, 0);
  CHECK(!boilerplate->map()->is_deprecated());

  // Serialize the elements.
1278
  Isolate* const isolate = broker->isolate();
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291
  Handle<FixedArrayBase> elements_object(boilerplate->elements(), isolate);

  // Boilerplates need special serialization - we need to make sure COW arrays
  // are tenured. Boilerplate objects should only be reachable from their
  // allocation site, so it is safe to assume that the elements have not been
  // serialized yet.

  bool const empty_or_cow =
      elements_object->length() == 0 ||
      elements_object->map() == ReadOnlyRoots(isolate).fixed_cow_array_map();
  if (empty_or_cow) {
    // We need to make sure copy-on-write elements are tenured.
    if (Heap::InNewSpace(*elements_object)) {
1292 1293
      elements_object = isolate->factory()->CopyAndTenureFixedCOWArray(
          Handle<FixedArray>::cast(elements_object));
1294 1295 1296 1297 1298
      boilerplate->set_elements(*elements_object);
    }
    cow_or_empty_elements_tenured_ = true;
  }

1299
  DCHECK_NULL(elements_);
1300
  elements_ = broker->GetOrCreateData(elements_object)->AsFixedArrayBase();
1301 1302 1303 1304 1305 1306

  if (empty_or_cow) {
    // No need to do anything here. Empty or copy-on-write elements
    // do not need to be serialized because we only need to store the elements
    // reference to the allocated object.
  } else if (boilerplate->HasSmiOrObjectElements()) {
1307
    elements_->AsFixedArray()->SerializeContents(broker);
1308 1309 1310 1311 1312 1313
    Handle<FixedArray> fast_elements =
        Handle<FixedArray>::cast(elements_object);
    int length = elements_object->length();
    for (int i = 0; i < length; i++) {
      Handle<Object> value(fast_elements->get(i), isolate);
      if (value->IsJSObject()) {
1314 1315
        ObjectData* value_data = broker->GetOrCreateData(value);
        value_data->AsJSObject()->SerializeRecursive(broker, depth - 1);
1316 1317 1318 1319 1320
      }
    }
  } else {
    CHECK(boilerplate->HasDoubleElements());
    CHECK_LE(elements_object->Size(), kMaxRegularHeapObjectSize);
1321
    elements_->AsFixedDoubleArray()->SerializeContents(broker);
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348
  }

  // TODO(turbofan): Do we want to support out-of-object properties?
  CHECK(boilerplate->HasFastProperties() &&
        boilerplate->property_array()->length() == 0);
  CHECK_EQ(inobject_fields_.size(), 0u);

  // Check the in-object properties.
  Handle<DescriptorArray> descriptors(
      boilerplate->map()->instance_descriptors(), isolate);
  int const limit = boilerplate->map()->NumberOfOwnDescriptors();
  for (int i = 0; i < limit; i++) {
    PropertyDetails details = descriptors->GetDetails(i);
    if (details.location() != kField) continue;
    DCHECK_EQ(kData, details.kind());

    FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
    // Make sure {field_index} agrees with {inobject_properties} on the index of
    // this field.
    DCHECK_EQ(field_index.property_index(),
              static_cast<int>(inobject_fields_.size()));
    if (boilerplate->IsUnboxedDoubleField(field_index)) {
      double value = boilerplate->RawFastDoublePropertyAt(field_index);
      inobject_fields_.push_back(JSObjectField{value});
    } else {
      Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
                           isolate);
1349
      ObjectData* value_data = broker->GetOrCreateData(value);
1350
      if (value->IsJSObject()) {
1351
        value_data->AsJSObject()->SerializeRecursive(broker, depth - 1);
1352 1353 1354 1355
      }
      inobject_fields_.push_back(JSObjectField{value_data});
    }
  }
1356
  broker->Trace("Copied %zu in-object fields.\n", inobject_fields_.size());
1357

1358
  map()->SerializeOwnDescriptors(broker);
1359

1360
  if (IsJSArray()) AsJSArray()->Serialize(broker);
1361 1362
}

1363
void JSRegExpData::SerializeAsRegExpBoilerplate(JSHeapBroker* broker) {
1364 1365
  if (serialized_as_reg_exp_boilerplate_) return;
  serialized_as_reg_exp_boilerplate_ = true;
1366

1367
  TraceScope tracer(broker, this, "JSRegExpData::SerializeAsRegExpBoilerplate");
1368 1369
  Handle<JSRegExp> boilerplate = Handle<JSRegExp>::cast(object());

1370
  SerializeElements(broker);
1371

1372
  raw_properties_or_hash_ =
1373 1374 1375 1376 1377
      broker->GetOrCreateData(boilerplate->raw_properties_or_hash());
  data_ = broker->GetOrCreateData(boilerplate->data());
  source_ = broker->GetOrCreateData(boilerplate->source());
  flags_ = broker->GetOrCreateData(boilerplate->flags());
  last_index_ = broker->GetOrCreateData(boilerplate->last_index());
1378 1379
}

1380
bool ObjectRef::equals(const ObjectRef& other) const {
1381
  return data_ == other.data_;
1382 1383
}

1384 1385
Isolate* ObjectRef::isolate() const { return broker()->isolate(); }

1386 1387 1388 1389
ContextRef ContextRef::previous() const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference handle_dereference;
1390 1391
    return ContextRef(broker(),
                      handle(object()->previous(), broker()->isolate()));
1392
  }
1393
  return ContextRef(broker(), data()->AsContext()->previous());
1394 1395
}

1396
// Not needed for TypedLowering.
1397
ObjectRef ContextRef::get(int index) const {
1398 1399
  AllowHandleAllocation handle_allocation;
  AllowHandleDereference handle_dereference;
1400
  Handle<Object> value(object()->get(index), broker()->isolate());
1401
  return ObjectRef(broker(), value);
1402 1403
}

1404 1405 1406 1407 1408
JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone)
    : isolate_(isolate),
      broker_zone_(broker_zone),
      current_zone_(broker_zone),
      refs_(new (zone())
1409 1410
                RefsMap(kMinimalRefsBucketCount, AddressMatcher(), zone())),
      array_and_object_prototypes_(zone()) {
1411 1412 1413 1414 1415
  // Note that this initialization of the refs_ pointer with the minimal
  // initial capacity is redundant in the normal use case (concurrent
  // compilation enabled, standard objects to be serialized), as the map
  // is going to be replaced immediatelly with a larger capacity one.
  // It doesn't seem to affect the performance in a noticeable way though.
1416
  Trace("Constructing heap broker.\n");
1417 1418 1419
}

void JSHeapBroker::Trace(const char* format, ...) const {
1420
  if (FLAG_trace_heap_broker) {
1421
    PrintF("[%p] ", this);
1422
    for (unsigned i = 0; i < tracing_indentation_; ++i) PrintF("  ");
1423 1424 1425 1426
    va_list arguments;
    va_start(arguments, format);
    base::OS::VPrint(format, arguments);
    va_end(arguments);
1427 1428 1429
  }
}

1430 1431 1432 1433
void JSHeapBroker::StartSerializing() {
  CHECK_EQ(mode_, kDisabled);
  Trace("Starting serialization.\n");
  mode_ = kSerializing;
1434
  refs_->Clear();
1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
}

void JSHeapBroker::StopSerializing() {
  CHECK_EQ(mode_, kSerializing);
  Trace("Stopping serialization.\n");
  mode_ = kSerialized;
}

void JSHeapBroker::Retire() {
  CHECK_EQ(mode_, kSerialized);
  Trace("Retiring.\n");
  mode_ = kRetired;
}

1449 1450 1451 1452 1453
bool JSHeapBroker::SerializingAllowed() const {
  return mode() == kSerializing ||
         (!FLAG_strict_heap_broker && mode() == kSerialized);
}

1454 1455 1456
void JSHeapBroker::SetNativeContextRef() {
  native_context_ = NativeContextRef(this, isolate()->native_context());
}
1457

1458 1459 1460 1461 1462 1463 1464
bool IsShareable(Handle<Object> object, Isolate* isolate) {
  Builtins* const b = isolate->builtins();

  int index;
  RootIndex root_index;
  return (object->IsHeapObject() &&
          b->IsBuiltinHandle(Handle<HeapObject>::cast(object), &index)) ||
1465
         isolate->roots_table().IsRootHandle(object, &root_index);
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
}

void JSHeapBroker::SerializeShareableObjects() {
  PerIsolateCompilerCache::Setup(isolate());
  compiler_cache_ = isolate()->compiler_cache();

  if (compiler_cache_->HasSnapshot()) {
    RefsMap* snapshot = compiler_cache_->GetSnapshot();

    refs_ = new (zone()) RefsMap(snapshot, zone());
    return;
  }

  TraceScope tracer(
      this, "JSHeapBroker::SerializeShareableObjects (building snapshot)");

  refs_ =
      new (zone()) RefsMap(kInitialRefsBucketCount, AddressMatcher(), zone());

  current_zone_ = compiler_cache_->zone();

  Builtins* const b = isolate()->builtins();
  {
    Builtins::Name builtins[] = {
        Builtins::kAllocateInNewSpace,
        Builtins::kAllocateInOldSpace,
        Builtins::kArgumentsAdaptorTrampoline,
        Builtins::kArrayConstructorImpl,
        Builtins::kCallFunctionForwardVarargs,
        Builtins::kCallFunction_ReceiverIsAny,
        Builtins::kCallFunction_ReceiverIsNotNullOrUndefined,
        Builtins::kCallFunction_ReceiverIsNullOrUndefined,
        Builtins::kConstructFunctionForwardVarargs,
        Builtins::kForInFilter,
        Builtins::kJSBuiltinsConstructStub,
        Builtins::kJSConstructStubGeneric,
        Builtins::kStringAdd_CheckNone,
        Builtins::kStringAdd_ConvertLeft,
        Builtins::kStringAdd_ConvertRight,
        Builtins::kToNumber,
        Builtins::kToObject,
    };
    for (auto id : builtins) {
      GetOrCreateData(b->builtin_handle(id));
    }
  }
  for (int32_t id = 0; id < Builtins::builtin_count; ++id) {
    if (Builtins::KindOf(id) == Builtins::TFJ) {
      GetOrCreateData(b->builtin_handle(id));
    }
  }

  for (RefsMap::Entry* p = refs_->Start(); p != nullptr; p = refs_->Next(p)) {
    CHECK(IsShareable(p->value->object(), isolate()));
  }

  // TODO(mslekova):
  // Serialize root objects (from factory).
  compiler_cache()->SetSnapshot(refs_);
  current_zone_ = broker_zone_;
}

1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
void JSHeapBroker::CollectArrayAndObjectPrototypes() {
  DisallowHeapAllocation no_gc;
  CHECK_EQ(mode(), kSerializing);
  CHECK(array_and_object_prototypes_.empty());

  Object* maybe_context = isolate()->heap()->native_contexts_list();
  while (!maybe_context->IsUndefined(isolate())) {
    Context* context = Context::cast(maybe_context);
    Object* array_prot = context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
    Object* object_prot = context->get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX);
    array_and_object_prototypes_.emplace(JSObject::cast(array_prot), isolate());
    array_and_object_prototypes_.emplace(JSObject::cast(object_prot),
                                         isolate());
    maybe_context = context->next_context_link();
  }

  CHECK(!array_and_object_prototypes_.empty());
}

bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
  if (mode() == kDisabled) {
    return isolate()->IsInAnyContext(*object.object(),
                                     Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
           isolate()->IsInAnyContext(*object.object(),
                                     Context::INITIAL_OBJECT_PROTOTYPE_INDEX);
  }
  CHECK(!array_and_object_prototypes_.empty());
1555
  return array_and_object_prototypes_.find(object.object()) !=
1556 1557 1558
         array_and_object_prototypes_.end();
}

1559
void JSHeapBroker::SerializeStandardObjects() {
1560
  if (mode() == kDisabled) return;
1561
  CHECK_EQ(mode(), kSerializing);
1562

1563 1564
  SerializeShareableObjects();

1565
  TraceScope tracer(this, "JSHeapBroker::SerializeStandardObjects");
1566

1567 1568
  CollectArrayAndObjectPrototypes();

1569
  SetNativeContextRef();
1570 1571
  native_context().Serialize();

1572 1573
  Factory* const f = isolate()->factory();

1574
  // Maps, strings, oddballs
1575
  GetOrCreateData(f->arguments_marker_map());
1576
  GetOrCreateData(f->bigint_string());
1577
  GetOrCreateData(f->block_context_map());
1578
  GetOrCreateData(f->boolean_map());
1579
  GetOrCreateData(f->boolean_string());
1580
  GetOrCreateData(f->catch_context_map());
1581 1582
  GetOrCreateData(f->empty_fixed_array());
  GetOrCreateData(f->empty_string());
1583
  GetOrCreateData(f->eval_context_map());
1584
  GetOrCreateData(f->false_string());
1585
  GetOrCreateData(f->false_value());
1586
  GetOrCreateData(f->fixed_array_map());
1587
  GetOrCreateData(f->fixed_cow_array_map());
1588 1589
  GetOrCreateData(f->fixed_double_array_map());
  GetOrCreateData(f->function_context_map());
1590 1591 1592
  GetOrCreateData(f->function_string());
  GetOrCreateData(f->heap_number_map());
  GetOrCreateData(f->length_string());
1593
  GetOrCreateData(f->many_closures_cell_map());
1594
  GetOrCreateData(f->minus_zero_value());
1595 1596
  GetOrCreateData(f->mutable_heap_number_map());
  GetOrCreateData(f->name_dictionary_map());
1597 1598
  GetOrCreateData(f->NaN_string());
  GetOrCreateData(f->null_map());
1599
  GetOrCreateData(f->null_string());
1600 1601 1602
  GetOrCreateData(f->null_value());
  GetOrCreateData(f->number_string());
  GetOrCreateData(f->object_string());
1603
  GetOrCreateData(f->one_pointer_filler_map());
1604
  GetOrCreateData(f->optimized_out());
1605
  GetOrCreateData(f->optimized_out_map());
1606
  GetOrCreateData(f->property_array_map());
1607
  GetOrCreateData(f->sloppy_arguments_elements_map());
1608
  GetOrCreateData(f->stale_register());
1609
  GetOrCreateData(f->stale_register_map());
1610 1611
  GetOrCreateData(f->string_string());
  GetOrCreateData(f->symbol_string());
1612 1613
  GetOrCreateData(f->termination_exception_map());
  GetOrCreateData(f->the_hole_map());
1614
  GetOrCreateData(f->the_hole_value());
1615
  GetOrCreateData(f->true_string());
1616
  GetOrCreateData(f->true_value());
1617
  GetOrCreateData(f->undefined_map());
1618
  GetOrCreateData(f->undefined_string());
1619
  GetOrCreateData(f->undefined_value());
1620
  GetOrCreateData(f->uninitialized_map());
1621
  GetOrCreateData(f->with_context_map());
1622
  GetOrCreateData(f->zero_string());
1623

1624
  // Protector cells
1625 1626
  GetOrCreateData(f->array_buffer_neutering_protector())
      ->AsPropertyCell()
1627
      ->Serialize(this);
1628
  GetOrCreateData(f->array_constructor_protector())->AsCell()->Serialize(this);
1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
  GetOrCreateData(f->array_iterator_protector())
      ->AsPropertyCell()
      ->Serialize(this);
  GetOrCreateData(f->array_species_protector())
      ->AsPropertyCell()
      ->Serialize(this);
  GetOrCreateData(f->no_elements_protector())
      ->AsPropertyCell()
      ->Serialize(this);
  GetOrCreateData(f->promise_hook_protector())
      ->AsPropertyCell()
      ->Serialize(this);
1641 1642
  GetOrCreateData(f->promise_species_protector())
      ->AsPropertyCell()
1643 1644 1645 1646
      ->Serialize(this);
  GetOrCreateData(f->promise_then_protector())
      ->AsPropertyCell()
      ->Serialize(this);
1647
  GetOrCreateData(f->string_length_protector())->AsCell()->Serialize(this);
1648

1649
  // CEntry stub
1650 1651 1652
  GetOrCreateData(
      CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs, kArgvOnStack, true));

1653
  Trace("Finished serializing standard objects.\n");
1654
}
1655

1656
ObjectData* JSHeapBroker::GetData(Handle<Object> object) const {
1657 1658
  RefsMap::Entry* entry = refs_->Lookup(object.address());
  return entry ? entry->value : nullptr;
1659 1660
}

1661
// clang-format off
1662
ObjectData* JSHeapBroker::GetOrCreateData(Handle<Object> object) {
1663
  CHECK(SerializingAllowed());
1664 1665 1666
  RefsMap::Entry* entry = refs_->LookupOrInsert(object.address(), zone());
  ObjectData** data_storage = &(entry->value);
  if (*data_storage == nullptr) {
1667 1668 1669
    // TODO(neis): Remove these Allow* once we serialize everything upfront.
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference handle_dereference;
1670
    if (object->IsSmi()) {
1671
      new (zone()) ObjectData(this, data_storage, object, kSmi);
1672 1673 1674
#define CREATE_DATA_IF_MATCH(name)                                             \
    } else if (object->Is##name()) {                                           \
      new (zone()) name##Data(this, data_storage, Handle<name>::cast(object));
1675 1676 1677 1678 1679
    HEAP_BROKER_OBJECT_LIST(CREATE_DATA_IF_MATCH)
#undef CREATE_DATA_IF_MATCH
    } else {
      UNREACHABLE();
    }
1680
  }
1681 1682
  CHECK_NOT_NULL(*data_storage);
  return (*data_storage);
1683
}
1684
// clang-format on
1685

1686 1687 1688 1689
ObjectData* JSHeapBroker::GetOrCreateData(Object* object) {
  return GetOrCreateData(handle(object, isolate()));
}

1690 1691 1692 1693
#define DEFINE_IS_AND_AS(Name)                                    \
  bool ObjectRef::Is##Name() const { return data()->Is##Name(); } \
  Name##Ref ObjectRef::As##Name() const {                         \
    DCHECK(Is##Name());                                           \
1694
    return Name##Ref(broker(), data());                           \
1695
  }
1696
HEAP_BROKER_OBJECT_LIST(DEFINE_IS_AND_AS)
1697
#undef DEFINE_IS_AND_AS
1698

1699
bool ObjectRef::IsSmi() const { return data()->is_smi(); }
1700 1701

int ObjectRef::AsSmi() const {
1702
  DCHECK(IsSmi());
1703
  // Handle-dereference is always allowed for Handle<Smi>.
1704
  return Handle<Smi>::cast(object())->value();
1705
}
1706

1707 1708 1709 1710 1711 1712
base::Optional<MapRef> JSObjectRef::GetObjectCreateMap() const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference allow_handle_dereference;
    AllowHeapAllocation heap_allocation;
    Handle<Map> instance_map;
1713
    if (Map::TryGetObjectCreateMap(broker()->isolate(), object())
1714 1715 1716 1717 1718
            .ToHandle(&instance_map)) {
      return MapRef(broker(), instance_map);
    } else {
      return base::Optional<MapRef>();
    }
1719
  }
1720
  MapData* map_data = data()->AsJSObject()->object_create_map();
1721 1722
  return map_data != nullptr ? MapRef(broker(), map_data)
                             : base::Optional<MapRef>();
1723 1724
}

1725 1726 1727 1728 1729 1730 1731
#define DEF_TESTER(Type, ...)                              \
  bool MapRef::Is##Type##Map() const {                     \
    return InstanceTypeChecker::Is##Type(instance_type()); \
  }
INSTANCE_TYPE_CHECKERS(DEF_TESTER)
#undef DEF_TESTER

1732
base::Optional<MapRef> MapRef::AsElementsKind(ElementsKind kind) const {
1733 1734 1735 1736
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHeapAllocation heap_allocation;
    AllowHandleDereference allow_handle_dereference;
1737 1738
    return MapRef(broker(),
                  Map::AsElementsKind(broker()->isolate(), object(), kind));
1739
  }
1740 1741 1742 1743 1744 1745 1746 1747
  if (kind == elements_kind()) return *this;
  const ZoneVector<MapData*>& elements_kind_generalizations =
      data()->AsMap()->elements_kind_generalizations();
  for (auto data : elements_kind_generalizations) {
    MapRef map(broker(), data);
    if (map.elements_kind() == kind) return map;
  }
  return base::Optional<MapRef>();
1748 1749
}

1750
int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const {
1751 1752 1753
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
    AllowHandleAllocation handle_allocation;
1754
    return object()->ComputeInstanceSizeWithMinSlack(broker()->isolate());
1755 1756
  }
  return data()->AsJSFunction()->initial_map_instance_size_with_min_slack();
1757 1758
}

1759
// Not needed for TypedLowering.
1760 1761
base::Optional<ScriptContextTableRef::LookupResult>
ScriptContextTableRef::lookup(const NameRef& name) const {
1762
  AllowHandleAllocation handle_allocation;
1763 1764 1765
  AllowHandleDereference handle_dereference;
  if (!name.IsString()) return {};
  ScriptContextTable::LookupResult lookup_result;
1766
  auto table = object();
1767
  if (!ScriptContextTable::Lookup(broker()->isolate(), table,
1768
                                  name.AsString().object(), &lookup_result)) {
1769 1770
    return {};
  }
1771 1772
  Handle<Context> script_context = ScriptContextTable::GetContext(
      broker()->isolate(), table, lookup_result.context_index);
1773
  LookupResult result{ContextRef(broker(), script_context),
1774 1775 1776 1777 1778
                      lookup_result.mode == VariableMode::kConst,
                      lookup_result.slot_index};
  return result;
}

1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
OddballType MapRef::oddball_type() const {
  if (instance_type() != ODDBALL_TYPE) {
    return OddballType::kNone;
  }
  Factory* f = broker()->isolate()->factory();
  if (equals(MapRef(broker(), f->undefined_map()))) {
    return OddballType::kUndefined;
  }
  if (equals(MapRef(broker(), f->null_map()))) {
    return OddballType::kNull;
  }
  if (equals(MapRef(broker(), f->boolean_map()))) {
    return OddballType::kBoolean;
  }
  if (equals(MapRef(broker(), f->the_hole_map()))) {
    return OddballType::kHole;
  }
  if (equals(MapRef(broker(), f->uninitialized_map()))) {
    return OddballType::kUninitialized;
  }
  DCHECK(equals(MapRef(broker(), f->termination_exception_map())) ||
         equals(MapRef(broker(), f->arguments_marker_map())) ||
         equals(MapRef(broker(), f->optimized_out_map())) ||
         equals(MapRef(broker(), f->stale_register_map())));
  return OddballType::kOther;
1804 1805
}

1806
ObjectRef FeedbackVectorRef::get(FeedbackSlot slot) const {
1807 1808 1809
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference handle_dereference;
1810
    Handle<Object> value(object()->Get(slot)->cast<Object>(),
1811 1812 1813 1814
                         broker()->isolate());
    return ObjectRef(broker(), value);
  }
  int i = FeedbackVector::GetIndex(slot);
1815
  return ObjectRef(broker(), data()->AsFeedbackVector()->feedback().at(i));
1816 1817 1818
}

double JSObjectRef::RawFastDoublePropertyAt(FieldIndex index) const {
1819 1820
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference handle_dereference;
1821
    return object()->RawFastDoublePropertyAt(index);
1822
  }
1823 1824 1825
  JSObjectData* object_data = data()->AsJSObject();
  CHECK(index.is_inobject());
  return object_data->GetInobjectField(index.property_index()).AsDouble();
1826 1827
}

1828
ObjectRef JSObjectRef::RawFastPropertyAt(FieldIndex index) const {
1829 1830 1831
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference handle_dereference;
1832 1833
    return ObjectRef(broker(), handle(object()->RawFastPropertyAt(index),
                                      broker()->isolate()));
1834
  }
1835 1836 1837
  JSObjectData* object_data = data()->AsJSObject();
  CHECK(index.is_inobject());
  return ObjectRef(
1838
      broker(),
1839
      object_data->GetInobjectField(index.property_index()).AsObject());
1840 1841
}

1842
bool AllocationSiteRef::IsFastLiteral() const {
1843
  if (broker()->mode() == JSHeapBroker::kDisabled) {
1844
    AllowHeapAllocation allow_heap_allocation;  // For TryMigrateInstance.
1845 1846 1847
    AllowHandleAllocation allow_handle_allocation;
    AllowHandleDereference allow_handle_dereference;
    return IsInlinableFastLiteral(
1848
        handle(object()->boilerplate(), broker()->isolate()));
1849
  }
1850
  return data()->AsAllocationSite()->IsFastLiteral();
1851 1852
}

1853
void JSObjectRef::EnsureElementsTenured() {
1854 1855 1856 1857 1858
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation allow_handle_allocation;
    AllowHandleDereference allow_handle_dereference;
    AllowHeapAllocation allow_heap_allocation;

1859
    Handle<FixedArrayBase> object_elements = elements().object();
1860 1861 1862 1863 1864 1865 1866
    if (Heap::InNewSpace(*object_elements)) {
      // If we would like to pretenure a fixed cow array, we must ensure that
      // the array is already in old space, otherwise we'll create too many
      // old-to-new-space pointers (overflowing the store buffer).
      object_elements =
          broker()->isolate()->factory()->CopyAndTenureFixedCOWArray(
              Handle<FixedArray>::cast(object_elements));
1867
      object()->set_elements(*object_elements);
1868
    }
1869
    return;
1870
  }
1871
  CHECK(data()->AsJSObject()->cow_or_empty_elements_tenured());
1872 1873
}

1874 1875 1876
FieldIndex MapRef::GetFieldIndexFor(int descriptor_index) const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
1877
    return FieldIndex::ForDescriptor(*object(), descriptor_index);
1878
  }
1879 1880
  DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
  return descriptors->contents().at(descriptor_index).field_index;
1881 1882
}

1883
int MapRef::GetInObjectPropertyOffset(int i) const {
1884 1885
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
1886
    return object()->GetInObjectPropertyOffset(i);
1887 1888
  }
  return (GetInObjectPropertiesStartInWords() + i) * kPointerSize;
1889 1890
}

1891 1892 1893
PropertyDetails MapRef::GetPropertyDetails(int descriptor_index) const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
1894
    return object()->instance_descriptors()->GetDetails(descriptor_index);
1895
  }
1896 1897
  DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
  return descriptors->contents().at(descriptor_index).details;
1898 1899
}

1900 1901 1902 1903 1904 1905
NameRef MapRef::GetPropertyKey(int descriptor_index) const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference allow_handle_dereference;
    return NameRef(
        broker(),
1906
        handle(object()->instance_descriptors()->GetKey(descriptor_index),
1907 1908
               broker()->isolate()));
  }
1909
  DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
1910
  return NameRef(broker(), descriptors->contents().at(descriptor_index).key);
1911 1912
}

1913
bool MapRef::IsFixedCowArrayMap() const {
1914 1915 1916
  Handle<Map> fixed_cow_array_map =
      ReadOnlyRoots(broker()->isolate()).fixed_cow_array_map_handle();
  return equals(MapRef(broker(), fixed_cow_array_map));
1917 1918
}

1919 1920 1921 1922
bool MapRef::IsPrimitiveMap() const {
  return instance_type() <= LAST_PRIMITIVE_TYPE;
}

1923 1924 1925 1926 1927
MapRef MapRef::FindFieldOwner(int descriptor_index) const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference allow_handle_dereference;
    Handle<Map> owner(
1928
        object()->FindFieldOwner(broker()->isolate(), descriptor_index),
1929 1930 1931
        broker()->isolate());
    return MapRef(broker(), owner);
  }
1932
  DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
1933 1934
  return MapRef(broker(),
                descriptors->contents().at(descriptor_index).field_owner);
1935 1936
}

1937 1938 1939 1940 1941
ObjectRef MapRef::GetFieldType(int descriptor_index) const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference allow_handle_dereference;
    Handle<FieldType> field_type(
1942
        object()->instance_descriptors()->GetFieldType(descriptor_index),
1943 1944 1945
        broker()->isolate());
    return ObjectRef(broker(), field_type);
  }
1946
  DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
1947 1948
  return ObjectRef(broker(),
                   descriptors->contents().at(descriptor_index).field_type);
1949 1950
}

1951 1952 1953
bool MapRef::IsUnboxedDoubleField(int descriptor_index) const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
1954 1955
    return object()->IsUnboxedDoubleField(
        FieldIndex::ForDescriptor(*object(), descriptor_index));
1956
  }
1957 1958
  DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
  return descriptors->contents().at(descriptor_index).is_unboxed_double_field;
1959 1960
}

1961
uint16_t StringRef::GetFirstChar() {
1962 1963
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
1964
    return object()->Get(0);
1965
  }
1966
  return data()->AsString()->first_char();
1967 1968
}

1969
base::Optional<double> StringRef::ToNumber() {
1970 1971 1972 1973 1974 1975
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
    AllowHandleAllocation allow_handle_allocation;
    AllowHeapAllocation allow_heap_allocation;
    int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
    return StringToDouble(broker()->isolate(),
1976 1977
                          broker()->isolate()->unicode_cache(), object(),
                          flags);
1978
  }
1979
  return data()->AsString()->to_number();
1980 1981
}

1982
ObjectRef FixedArrayRef::get(int i) const {
1983 1984 1985
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference allow_handle_dereference;
1986
    return ObjectRef(broker(), handle(object()->get(i), broker()->isolate()));
1987
  }
1988
  return ObjectRef(broker(), data()->AsFixedArray()->Get(i));
1989 1990 1991
}

bool FixedDoubleArrayRef::is_the_hole(int i) const {
1992 1993
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
1994
    return object()->is_the_hole(i);
1995
  }
1996
  return data()->AsFixedDoubleArray()->Get(i).is_hole_nan();
1997 1998 1999
}

double FixedDoubleArrayRef::get_scalar(int i) const {
2000 2001
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
2002
    return object()->get_scalar(i);
2003
  }
2004 2005
  CHECK(!data()->AsFixedDoubleArray()->Get(i).is_hole_nan());
  return data()->AsFixedDoubleArray()->Get(i).get_scalar();
2006 2007
}

2008 2009 2010 2011
#define IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name) \
  if (broker()->mode() == JSHeapBroker::kDisabled) {     \
    AllowHandleAllocation handle_allocation;             \
    AllowHandleDereference allow_handle_dereference;     \
2012
    return object()->name();                             \
2013 2014
  }

2015 2016 2017 2018 2019 2020
#define IF_BROKER_DISABLED_ACCESS_HANDLE(holder, result, name)         \
  if (broker()->mode() == JSHeapBroker::kDisabled) {                   \
    AllowHandleAllocation handle_allocation;                           \
    AllowHandleDereference allow_handle_dereference;                   \
    return result##Ref(broker(),                                       \
                       handle(object()->name(), broker()->isolate())); \
2021 2022
  }

2023
// Macros for definining a const getter that, depending on the broker mode,
2024
// either looks into the handle or into the serialized data.
2025 2026 2027 2028
#define BIMODAL_ACCESSOR(holder, result, name)                             \
  result##Ref holder##Ref::name() const {                                  \
    IF_BROKER_DISABLED_ACCESS_HANDLE(holder, result, name);                \
    return result##Ref(broker(), ObjectRef::data()->As##holder()->name()); \
2029 2030
  }

2031
// Like above except that the result type is not an XYZRef.
2032 2033 2034
#define BIMODAL_ACCESSOR_C(holder, result, name)      \
  result holder##Ref::name() const {                  \
    IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name); \
2035
    return ObjectRef::data()->As##holder()->name();   \
2036 2037
  }

2038
// Like above but for BitFields.
2039 2040 2041 2042
#define BIMODAL_ACCESSOR_B(holder, field, name, BitField)              \
  typename BitField::FieldType holder##Ref::name() const {             \
    IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name);                  \
    return BitField::decode(ObjectRef::data()->As##holder()->field()); \
2043 2044
  }

2045 2046 2047 2048 2049
BIMODAL_ACCESSOR(AllocationSite, Object, nested_site)
BIMODAL_ACCESSOR_C(AllocationSite, bool, CanInlineCall)
BIMODAL_ACCESSOR_C(AllocationSite, bool, PointsToLiteral)
BIMODAL_ACCESSOR_C(AllocationSite, ElementsKind, GetElementsKind)
BIMODAL_ACCESSOR_C(AllocationSite, PretenureFlag, GetPretenureMode)
2050

2051 2052
BIMODAL_ACCESSOR_C(BytecodeArray, int, register_count)

2053 2054
BIMODAL_ACCESSOR(Cell, Object, value)

2055 2056
BIMODAL_ACCESSOR(HeapObject, Map, map)

2057
BIMODAL_ACCESSOR(JSArray, Object, length)
2058

2059 2060 2061
BIMODAL_ACCESSOR_C(JSFunction, bool, has_prototype)
BIMODAL_ACCESSOR_C(JSFunction, bool, has_initial_map)
BIMODAL_ACCESSOR_C(JSFunction, bool, PrototypeRequiresRuntimeLookup)
2062
BIMODAL_ACCESSOR(JSFunction, NativeContext, native_context)
2063 2064 2065
BIMODAL_ACCESSOR(JSFunction, Map, initial_map)
BIMODAL_ACCESSOR(JSFunction, Object, prototype)
BIMODAL_ACCESSOR(JSFunction, SharedFunctionInfo, shared)
2066

2067 2068 2069 2070
BIMODAL_ACCESSOR_C(JSTypedArray, bool, is_on_heap)
BIMODAL_ACCESSOR_C(JSTypedArray, size_t, length_value)
BIMODAL_ACCESSOR(JSTypedArray, HeapObject, buffer)

2071
BIMODAL_ACCESSOR_B(Map, bit_field2, elements_kind, Map::ElementsKindBits)
2072
BIMODAL_ACCESSOR_B(Map, bit_field2, is_extensible, Map::IsExtensibleBit)
2073 2074
BIMODAL_ACCESSOR_B(Map, bit_field3, is_deprecated, Map::IsDeprecatedBit)
BIMODAL_ACCESSOR_B(Map, bit_field3, is_dictionary_map, Map::IsDictionaryMapBit)
2075 2076
BIMODAL_ACCESSOR_B(Map, bit_field3, NumberOfOwnDescriptors,
                   Map::NumberOfOwnDescriptorsBits)
2077
BIMODAL_ACCESSOR_B(Map, bit_field, has_prototype_slot, Map::HasPrototypeSlotBit)
2078 2079
BIMODAL_ACCESSOR_B(Map, bit_field, is_access_check_needed,
                   Map::IsAccessCheckNeededBit)
2080
BIMODAL_ACCESSOR_B(Map, bit_field, is_callable, Map::IsCallableBit)
2081
BIMODAL_ACCESSOR_B(Map, bit_field, is_constructor, Map::IsConstructorBit)
2082
BIMODAL_ACCESSOR_B(Map, bit_field, is_undetectable, Map::IsUndetectableBit)
2083
BIMODAL_ACCESSOR_C(Map, int, instance_size)
2084
BIMODAL_ACCESSOR(Map, Object, prototype)
2085
BIMODAL_ACCESSOR_C(Map, InstanceType, instance_type)
2086
BIMODAL_ACCESSOR(Map, Object, GetConstructor)
2087

2088
#define DEF_NATIVE_CONTEXT_ACCESSOR(type, name) \
2089
  BIMODAL_ACCESSOR(NativeContext, type, name)
2090 2091
BROKER_NATIVE_CONTEXT_FIELDS(DEF_NATIVE_CONTEXT_ACCESSOR)
#undef DEF_NATIVE_CONTEXT_ACCESSOR
2092

2093 2094
BIMODAL_ACCESSOR(PropertyCell, Object, value)
BIMODAL_ACCESSOR_C(PropertyCell, PropertyDetails, property_details)
2095

2096
BIMODAL_ACCESSOR_C(SharedFunctionInfo, int, builtin_id)
2097
BIMODAL_ACCESSOR(SharedFunctionInfo, BytecodeArray, GetBytecodeArray)
2098 2099 2100 2101
#define DEF_SFI_ACCESSOR(type, name) \
  BIMODAL_ACCESSOR_C(SharedFunctionInfo, type, name)
BROKER_SFI_FIELDS(DEF_SFI_ACCESSOR)
#undef DEF_SFI_ACCESSOR
2102

2103 2104
BIMODAL_ACCESSOR_C(String, int, length)

2105 2106 2107
void* JSTypedArrayRef::elements_external_pointer() const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
2108
    return FixedTypedArrayBase::cast(object()->elements())->external_pointer();
2109 2110 2111 2112
  }
  return data()->AsJSTypedArray()->elements_external_pointer();
}

2113 2114 2115 2116 2117 2118
bool MapRef::IsInobjectSlackTrackingInProgress() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, IsInobjectSlackTrackingInProgress);
  return Map::ConstructionCounterBits::decode(data()->AsMap()->bit_field3()) !=
         Map::kNoSlackTracking;
}

2119 2120 2121 2122 2123 2124
int MapRef::constructor_function_index() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, GetConstructorFunctionIndex);
  CHECK(IsPrimitiveMap());
  return data()->AsMap()->constructor_function_index();
}

2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155
bool MapRef::is_stable() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, is_stable);
  return !Map::IsUnstableBit::decode(data()->AsMap()->bit_field3());
}

bool MapRef::CanBeDeprecated() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, CanBeDeprecated);
  CHECK_GT(NumberOfOwnDescriptors(), 0);
  return data()->AsMap()->can_be_deprecated();
}

bool MapRef::CanTransition() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, CanTransition);
  return data()->AsMap()->can_transition();
}

int MapRef::GetInObjectPropertiesStartInWords() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, GetInObjectPropertiesStartInWords);
  return data()->AsMap()->in_object_properties_start_in_words();
}

int MapRef::GetInObjectProperties() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, GetInObjectProperties);
  return data()->AsMap()->in_object_properties();
}

int ScopeInfoRef::ContextLength() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(ScopeInfo, ContextLength);
  return data()->AsScopeInfo()->context_length();
}

2156 2157 2158 2159 2160 2161 2162 2163 2164 2165
bool StringRef::IsExternalString() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(String, IsExternalString);
  return data()->AsString()->is_external_string();
}

bool StringRef::IsSeqString() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(String, IsSeqString);
  return data()->AsString()->is_seq_string();
}

2166
MapRef NativeContextRef::GetFunctionMapFromIndex(int index) const {
2167
  DCHECK_GE(index, Context::FIRST_FUNCTION_MAP_INDEX);
2168
  DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX);
2169 2170 2171
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    return get(index).AsMap();
  }
2172 2173
  return MapRef(broker(), data()->AsNativeContext()->function_maps().at(
                              index - Context::FIRST_FUNCTION_MAP_INDEX));
2174 2175
}

2176
MapRef NativeContextRef::GetInitialJSArrayMap(ElementsKind kind) const {
2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192
  switch (kind) {
    case PACKED_SMI_ELEMENTS:
      return js_array_packed_smi_elements_map();
    case HOLEY_SMI_ELEMENTS:
      return js_array_holey_smi_elements_map();
    case PACKED_DOUBLE_ELEMENTS:
      return js_array_packed_double_elements_map();
    case HOLEY_DOUBLE_ELEMENTS:
      return js_array_holey_double_elements_map();
    case PACKED_ELEMENTS:
      return js_array_packed_elements_map();
    case HOLEY_ELEMENTS:
      return js_array_holey_elements_map();
    default:
      UNREACHABLE();
  }
2193 2194
}

2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215
base::Optional<JSFunctionRef> NativeContextRef::GetConstructorFunction(
    const MapRef& map) const {
  CHECK(map.IsPrimitiveMap());
  switch (map.constructor_function_index()) {
    case Map::kNoConstructorFunctionIndex:
      return base::nullopt;
    case Context::BIGINT_FUNCTION_INDEX:
      return bigint_function();
    case Context::BOOLEAN_FUNCTION_INDEX:
      return boolean_function();
    case Context::NUMBER_FUNCTION_INDEX:
      return number_function();
    case Context::STRING_FUNCTION_INDEX:
      return string_function();
    case Context::SYMBOL_FUNCTION_INDEX:
      return symbol_function();
    default:
      UNREACHABLE();
  }
}

2216 2217 2218
bool ObjectRef::BooleanValue() const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference allow_handle_dereference;
2219
    return object()->BooleanValue(broker()->isolate());
2220 2221
  }
  return IsSmi() ? (AsSmi() != 0) : data()->AsHeapObject()->boolean_value();
2222 2223
}

2224
double ObjectRef::OddballToNumber() const {
2225
  OddballType type = AsHeapObject().map().oddball_type();
2226 2227 2228

  switch (type) {
    case OddballType::kBoolean: {
2229 2230
      ObjectRef true_ref(broker(),
                         broker()->isolate()->factory()->true_value());
2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248
      return this->equals(true_ref) ? 1 : 0;
      break;
    }
    case OddballType::kUndefined: {
      return std::numeric_limits<double>::quiet_NaN();
      break;
    }
    case OddballType::kNull: {
      return 0;
      break;
    }
    default: {
      UNREACHABLE();
      break;
    }
  }
}

2249 2250 2251 2252 2253 2254 2255 2256 2257 2258
double HeapNumberRef::value() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(HeapNumber, value);
  return data()->AsHeapNumber()->value();
}

double MutableHeapNumberRef::value() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(MutableHeapNumber, value);
  return data()->AsMutableHeapNumber()->value();
}

2259 2260 2261 2262
CellRef ModuleRef::GetCell(int cell_index) const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference allow_handle_dereference;
2263 2264
    return CellRef(broker(),
                   handle(object()->GetCell(cell_index), broker()->isolate()));
2265
  }
2266
  return CellRef(broker(), data()->AsModule()->GetCell(cell_index));
2267 2268
}

2269 2270
ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object)
    : broker_(broker) {
2271 2272
  switch (broker->mode()) {
    case JSHeapBroker::kSerialized:
2273 2274
      data_ = FLAG_strict_heap_broker ? broker->GetData(object)
                                      : broker->GetOrCreateData(object);
2275 2276 2277 2278
      break;
    case JSHeapBroker::kSerializing:
      data_ = broker->GetOrCreateData(object);
      break;
2279
    case JSHeapBroker::kDisabled: {
2280 2281 2282 2283
      RefsMap::Entry* entry =
          broker->refs_->LookupOrInsert(object.address(), broker->zone());
      ObjectData** storage = &(entry->value);
      if (*storage == nullptr) {
2284
        AllowHandleDereference handle_dereference;
2285 2286
        entry->value = new (broker->zone())
            ObjectData(broker, storage, object,
2287
                       object->IsSmi() ? kSmi : kUnserializedHeapObject);
2288
      }
2289
      data_ = *storage;
2290
      break;
2291 2292 2293
    }
    case JSHeapBroker::kRetired:
      UNREACHABLE();
2294 2295 2296 2297
  }
  CHECK_NOT_NULL(data_);
}

2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340
namespace {
OddballType GetOddballType(Isolate* isolate, Map* map) {
  if (map->instance_type() != ODDBALL_TYPE) {
    return OddballType::kNone;
  }
  ReadOnlyRoots roots(isolate);
  if (map == roots.undefined_map()) {
    return OddballType::kUndefined;
  }
  if (map == roots.null_map()) {
    return OddballType::kNull;
  }
  if (map == roots.boolean_map()) {
    return OddballType::kBoolean;
  }
  if (map == roots.the_hole_map()) {
    return OddballType::kHole;
  }
  if (map == roots.uninitialized_map()) {
    return OddballType::kUninitialized;
  }
  DCHECK(map == roots.termination_exception_map() ||
         map == roots.arguments_marker_map() ||
         map == roots.optimized_out_map() || map == roots.stale_register_map());
  return OddballType::kOther;
}
}  // namespace

HeapObjectType HeapObjectRef::GetHeapObjectType() const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleDereference handle_dereference;
    Map* map = Handle<HeapObject>::cast(object())->map();
    HeapObjectType::Flags flags(0);
    if (map->is_undetectable()) flags |= HeapObjectType::kUndetectable;
    if (map->is_callable()) flags |= HeapObjectType::kCallable;
    return HeapObjectType(map->instance_type(), flags,
                          GetOddballType(broker()->isolate(), map));
  }
  HeapObjectType::Flags flags(0);
  if (map().is_undetectable()) flags |= HeapObjectType::kUndetectable;
  if (map().is_callable()) flags |= HeapObjectType::kCallable;
  return HeapObjectType(map().instance_type(), flags, map().oddball_type());
}
2341 2342 2343 2344
base::Optional<JSObjectRef> AllocationSiteRef::boilerplate() const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference allow_handle_dereference;
2345 2346
    return JSObjectRef(broker(),
                       handle(object()->boilerplate(), broker()->isolate()));
2347 2348 2349
  }
  JSObjectData* boilerplate = data()->AsAllocationSite()->boilerplate();
  if (boilerplate) {
2350
    return JSObjectRef(broker(), boilerplate);
2351
  } else {
2352
    return base::nullopt;
2353 2354 2355
  }
}

2356 2357 2358 2359
ElementsKind JSObjectRef::GetElementsKind() const {
  return map().elements_kind();
}

2360 2361 2362 2363
FixedArrayBaseRef JSObjectRef::elements() const {
  if (broker()->mode() == JSHeapBroker::kDisabled) {
    AllowHandleAllocation handle_allocation;
    AllowHandleDereference allow_handle_dereference;
2364 2365
    return FixedArrayBaseRef(broker(),
                             handle(object()->elements(), broker()->isolate()));
2366
  }
2367
  return FixedArrayBaseRef(broker(), data()->AsJSObject()->elements());
2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386
}

int FixedArrayBaseRef::length() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE_C(FixedArrayBase, length);
  return data()->AsFixedArrayBase()->length();
}

ObjectData* FixedArrayData::Get(int i) const {
  CHECK_LT(i, static_cast<int>(contents_.size()));
  CHECK_NOT_NULL(contents_[i]);
  return contents_[i];
}

Float64 FixedDoubleArrayData::Get(int i) const {
  CHECK_LT(i, static_cast<int>(contents_.size()));
  return contents_[i];
}

void FeedbackVectorRef::SerializeSlots() {
2387
  data()->AsFeedbackVector()->SerializeSlots(broker());
2388 2389
}

2390 2391
ObjectRef JSRegExpRef::data() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, data);
2392
  return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->data());
2393 2394 2395 2396
}

ObjectRef JSRegExpRef::flags() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, flags);
2397
  return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->flags());
2398 2399 2400 2401
}

ObjectRef JSRegExpRef::last_index() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, last_index);
2402
  return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->last_index());
2403 2404 2405 2406
}

ObjectRef JSRegExpRef::raw_properties_or_hash() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, raw_properties_or_hash);
2407 2408
  return ObjectRef(broker(),
                   ObjectRef::data()->AsJSRegExp()->raw_properties_or_hash());
2409 2410 2411 2412
}

ObjectRef JSRegExpRef::source() const {
  IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, source);
2413
  return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->source());
2414 2415
}

2416
Handle<Object> ObjectRef::object() const { return data_->object(); }
2417

2418 2419 2420 2421 2422 2423 2424
#define DEF_OBJECT_GETTER(T)                                            \
  Handle<T> T##Ref::object() const {                                    \
    return Handle<T>(reinterpret_cast<T**>(data_->object().address())); \
  }
HEAP_BROKER_OBJECT_LIST(DEF_OBJECT_GETTER)
#undef DEF_OBJECT_GETTER

2425
JSHeapBroker* ObjectRef::broker() const { return broker_; }
2426

2427
ObjectData* ObjectRef::data() const {
2428
  switch (broker()->mode()) {
2429 2430 2431 2432 2433 2434 2435 2436
    case JSHeapBroker::kDisabled:
      CHECK_NE(data_->kind(), kSerializedHeapObject);
      return data_;
    case JSHeapBroker::kSerializing:
    case JSHeapBroker::kSerialized:
      CHECK_NE(data_->kind(), kUnserializedHeapObject);
      return data_;
    case JSHeapBroker::kRetired:
2437
      UNREACHABLE();
2438 2439
  }
}
2440

2441 2442 2443 2444 2445 2446 2447 2448 2449
Reduction NoChangeBecauseOfMissingData(JSHeapBroker* broker,
                                       const char* function, int line) {
  if (FLAG_trace_heap_broker) {
    PrintF("[%p] Skipping optimization in %s at line %d due to missing data\n",
           broker, function, line);
  }
  return AdvancedReducer::NoChange();
}

2450
NativeContextData::NativeContextData(JSHeapBroker* broker, ObjectData** storage,
2451
                                     Handle<NativeContext> object)
2452
    : ContextData(broker, storage, object), function_maps_(broker->zone()) {}
2453

2454
void NativeContextData::Serialize(JSHeapBroker* broker) {
2455 2456 2457
  if (serialized_) return;
  serialized_ = true;

2458
  TraceScope tracer(broker, this, "NativeContextData::Serialize");
2459
  Handle<NativeContext> context = Handle<NativeContext>::cast(object());
2460

2461 2462 2463 2464 2465
#define SERIALIZE_MEMBER(type, name)                                       \
  DCHECK_NULL(name##_);                                                    \
  name##_ = broker->GetOrCreateData(context->name())->As##type();          \
  if (name##_->IsJSFunction()) name##_->AsJSFunction()->Serialize(broker); \
  if (name##_->IsMap()) name##_->AsMap()->SerializeConstructor(broker);
2466 2467 2468 2469
  BROKER_COMPULSORY_NATIVE_CONTEXT_FIELDS(SERIALIZE_MEMBER)
  if (!broker->isolate()->bootstrapper()->IsActive()) {
    BROKER_OPTIONAL_NATIVE_CONTEXT_FIELDS(SERIALIZE_MEMBER)
  }
2470
#undef SERIALIZE_MEMBER
2471

2472 2473 2474
  bound_function_with_constructor_map_->SerializePrototype(broker);
  bound_function_without_constructor_map_->SerializePrototype(broker);

2475 2476 2477 2478 2479
  DCHECK(function_maps_.empty());
  int const first = Context::FIRST_FUNCTION_MAP_INDEX;
  int const last = Context::LAST_FUNCTION_MAP_INDEX;
  function_maps_.reserve(last + 1 - first);
  for (int i = first; i <= last; ++i) {
2480
    function_maps_.push_back(broker->GetOrCreateData(context->get(i))->AsMap());
2481
  }
2482 2483 2484 2485 2486
}

void JSFunctionRef::Serialize() {
  if (broker()->mode() == JSHeapBroker::kDisabled) return;
  CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2487
  data()->AsJSFunction()->Serialize(broker());
2488 2489
}

2490 2491 2492
void JSObjectRef::SerializeObjectCreateMap() {
  if (broker()->mode() == JSHeapBroker::kDisabled) return;
  CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2493
  data()->AsJSObject()->SerializeObjectCreateMap(broker());
2494 2495
}

2496
void MapRef::SerializeOwnDescriptors() {
2497 2498
  if (broker()->mode() == JSHeapBroker::kDisabled) return;
  CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2499
  data()->AsMap()->SerializeOwnDescriptors(broker());
2500 2501
}

2502 2503 2504 2505 2506 2507
void MapRef::SerializePrototype() {
  if (broker()->mode() == JSHeapBroker::kDisabled) return;
  CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
  data()->AsMap()->SerializePrototype(broker());
}

2508 2509 2510
void ModuleRef::Serialize() {
  if (broker()->mode() == JSHeapBroker::kDisabled) return;
  CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2511
  data()->AsModule()->Serialize(broker());
2512 2513
}

2514 2515 2516
void ContextRef::Serialize() {
  if (broker()->mode() == JSHeapBroker::kDisabled) return;
  CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2517
  data()->AsContext()->Serialize(broker());
2518 2519
}

2520 2521 2522
void NativeContextRef::Serialize() {
  if (broker()->mode() == JSHeapBroker::kDisabled) return;
  CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2523
  data()->AsNativeContext()->Serialize(broker());
2524 2525
}

2526 2527 2528 2529 2530 2531
void JSTypedArrayRef::Serialize() {
  if (broker()->mode() == JSHeapBroker::kDisabled) return;
  CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
  data()->AsJSTypedArray()->Serialize(broker());
}

2532
#undef BIMODAL_ACCESSOR
2533 2534
#undef BIMODAL_ACCESSOR_B
#undef BIMODAL_ACCESSOR_C
2535
#undef IF_BROKER_DISABLED_ACCESS_HANDLE
2536
#undef IF_BROKER_DISABLED_ACCESS_HANDLE_C
2537

2538 2539 2540
}  // namespace compiler
}  // namespace internal
}  // namespace v8