• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/compiler/js-heap-broker.h"
6 #include "src/common/globals.h"
7 #include "src/compiler/heap-refs.h"
8 
9 #ifdef ENABLE_SLOW_DCHECKS
10 #include <algorithm>
11 #endif
12 
13 #include "include/v8-fast-api-calls.h"
14 #include "src/api/api-inl.h"
15 #include "src/ast/modules.h"
16 #include "src/codegen/code-factory.h"
17 #include "src/codegen/optimized-compilation-info.h"
18 #include "src/compiler/access-info.h"
19 #include "src/compiler/bytecode-analysis.h"
20 #include "src/compiler/graph-reducer.h"
21 #include "src/compiler/per-isolate-compiler-cache.h"
22 #include "src/execution/protectors-inl.h"
23 #include "src/init/bootstrapper.h"
24 #include "src/objects/allocation-site-inl.h"
25 #include "src/objects/api-callbacks.h"
26 #include "src/objects/cell-inl.h"
27 #include "src/objects/heap-number-inl.h"
28 #include "src/objects/instance-type-inl.h"
29 #include "src/objects/js-array-buffer-inl.h"
30 #include "src/objects/js-array-inl.h"
31 #include "src/objects/js-regexp-inl.h"
32 #include "src/objects/literal-objects-inl.h"
33 #include "src/objects/module-inl.h"
34 #include "src/objects/objects-inl.h"
35 #include "src/objects/template-objects-inl.h"
36 #include "src/objects/templates.h"
37 #include "src/utils/utils.h"
38 
39 namespace v8 {
40 namespace internal {
41 namespace compiler {
42 
43 #define TRACE(broker, x) TRACE_BROKER(broker, x)
44 #define TRACE_MISSING(broker, x) TRACE_BROKER_MISSING(broker, x)
45 
46 #define FORWARD_DECL(Name) class Name##Data;
47 HEAP_BROKER_SERIALIZED_OBJECT_LIST(FORWARD_DECL)
48 // TODO(solanes, v8:10866): Remove once FLAG_turbo_direct_heap_access is
49 // removed.
50 HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(FORWARD_DECL)
51 #undef FORWARD_DECL
52 
53 // There are five kinds of ObjectData values.
54 //
55 // kSmi: The underlying V8 object is a Smi and the data is an instance of the
56 //   base class (ObjectData), i.e. it's basically just the handle.  Because the
57 //   object is a Smi, it's safe to access the handle in order to extract the
58 //   number value, and AsSmi() does exactly that.
59 //
60 // kSerializedHeapObject: The underlying V8 object is a HeapObject and the
61 //   data is an instance of the corresponding (most-specific) subclass, e.g.
62 //   JSFunctionData, which provides serialized information about the object.
63 //
64 // kUnserializedHeapObject: The underlying V8 object is a HeapObject and the
65 //   data is an instance of the base class (ObjectData), i.e. it basically
66 //   carries no information other than the handle.
67 //
68 // kNeverSerializedHeapObject: The underlying V8 object is a (potentially
69 //   mutable) HeapObject and the data is an instance of ObjectData. Its handle
70 //   must be persistent so that the GC can update it at a safepoint. Via this
71 //   handle, the object can be accessed concurrently to the main thread. To be
72 //   used the flag --turbo-direct-heap-access must be on.
73 //
74 // kUnserializedReadOnlyHeapObject: The underlying V8 object is a read-only
75 //   HeapObject and the data is an instance of ObjectData. For
76 //   ReadOnlyHeapObjects, it is OK to access heap even from off-thread, so
77 //   these objects need not be serialized.
78 enum ObjectDataKind {
79   kSmi,
80   kSerializedHeapObject,
81   kUnserializedHeapObject,
82   kNeverSerializedHeapObject,
83   kUnserializedReadOnlyHeapObject
84 };
85 
86 class AllowHandleAllocationIfNeeded {
87  public:
AllowHandleAllocationIfNeeded(ObjectDataKind kind,JSHeapBroker::BrokerMode mode,bool direct_heap_access=false)88   explicit AllowHandleAllocationIfNeeded(ObjectDataKind kind,
89                                          JSHeapBroker::BrokerMode mode,
90                                          bool direct_heap_access = false) {
91     DCHECK_IMPLIES(mode == JSHeapBroker::BrokerMode::kSerialized,
92                    kind == kUnserializedReadOnlyHeapObject ||
93                        kind == kNeverSerializedHeapObject ||
94                        (direct_heap_access && kind == kSerializedHeapObject));
95     if (kind == kUnserializedHeapObject) maybe_allow_handle_.emplace();
96   }
97 
98  private:
99   base::Optional<AllowHandleAllocation> maybe_allow_handle_;
100 };
101 
102 class AllowHandleDereferenceIfNeeded {
103  public:
AllowHandleDereferenceIfNeeded(ObjectDataKind kind,JSHeapBroker::BrokerMode mode,bool direct_heap_access=false)104   explicit AllowHandleDereferenceIfNeeded(ObjectDataKind kind,
105                                           JSHeapBroker::BrokerMode mode,
106                                           bool direct_heap_access = false)
107       : AllowHandleDereferenceIfNeeded(kind) {
108     DCHECK_IMPLIES(mode == JSHeapBroker::BrokerMode::kSerialized,
109                    kind == kUnserializedReadOnlyHeapObject ||
110                        kind == kNeverSerializedHeapObject ||
111                        (direct_heap_access && kind == kSerializedHeapObject));
112   }
113 
AllowHandleDereferenceIfNeeded(ObjectDataKind kind)114   explicit AllowHandleDereferenceIfNeeded(ObjectDataKind kind) {
115     if (kind == kUnserializedHeapObject ||
116         kind == kUnserializedReadOnlyHeapObject) {
117       maybe_allow_handle_.emplace();
118     }
119   }
120 
121  private:
122   base::Optional<AllowHandleDereference> maybe_allow_handle_;
123 };
124 
125 class AllowHeapAllocationIfNeeded {
126  public:
AllowHeapAllocationIfNeeded(ObjectDataKind kind,JSHeapBroker::BrokerMode mode)127   explicit AllowHeapAllocationIfNeeded(ObjectDataKind kind,
128                                        JSHeapBroker::BrokerMode mode) {
129     DCHECK_IMPLIES(mode == JSHeapBroker::BrokerMode::kSerialized,
130                    kind == kUnserializedReadOnlyHeapObject);
131     if (kind == kUnserializedHeapObject) maybe_allow_handle_.emplace();
132   }
133 
134  private:
135   base::Optional<AllowHeapAllocation> maybe_allow_handle_;
136 };
137 
138 namespace {
IsReadOnlyHeapObject(Object object)139 bool IsReadOnlyHeapObject(Object object) {
140   DisallowHeapAllocation no_gc;
141   return (object.IsCode() && Code::cast(object).is_builtin()) ||
142          (object.IsHeapObject() &&
143           ReadOnlyHeap::Contains(HeapObject::cast(object)));
144 }
145 }  // namespace
146 
147 class ObjectData : public ZoneObject {
148  public:
ObjectData(JSHeapBroker * broker,ObjectData ** storage,Handle<Object> object,ObjectDataKind kind)149   ObjectData(JSHeapBroker* broker, ObjectData** storage, Handle<Object> object,
150              ObjectDataKind kind)
151       : object_(object), kind_(kind) {
152     // This assignment ensures we don't end up inserting the same object
153     // in an endless recursion.
154     *storage = this;
155 
156     TRACE(broker, "Creating data " << this << " for handle " << object.address()
157                                    << " (" << Brief(*object) << ")");
158 
159     // It is safe to access read only heap objects and builtins from a
160     // background thread. When we read fileds of these objects, we may create
161     // ObjectData on the background thread even without a canonical handle
162     // scope. This is safe too since we don't create handles but just get
163     // handles from read only root table or builtins table which is what
164     // canonical scope uses as well. For all other objects we should have
165     // created ObjectData in canonical handle scope on the main thread.
166     CHECK_IMPLIES(
167         broker->mode() == JSHeapBroker::kDisabled ||
168             broker->mode() == JSHeapBroker::kSerializing,
169         broker->isolate()->handle_scope_data()->canonical_scope != nullptr);
170     CHECK_IMPLIES(broker->mode() == JSHeapBroker::kSerialized,
171                   (kind == kUnserializedReadOnlyHeapObject &&
172                    IsReadOnlyHeapObject(*object)) ||
173                       kind == kNeverSerializedHeapObject);
174   }
175 
176 #define DECLARE_IS(Name) bool Is##Name() const;
177   HEAP_BROKER_SERIALIZED_OBJECT_LIST(DECLARE_IS)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DECLARE_IS)178   HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DECLARE_IS)
179 #undef DECLARE_IS
180 
181 #define DECLARE_AS(Name) Name##Data* As##Name();
182   HEAP_BROKER_SERIALIZED_OBJECT_LIST(DECLARE_AS)
183   // TODO(solanes, v8:10866): Remove once FLAG_turbo_direct_heap_access is
184   // removed.
185   HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DECLARE_AS)
186 #undef DECLARE_AS
187 
188   Handle<Object> object() const { return object_; }
kind() const189   ObjectDataKind kind() const { return kind_; }
is_smi() const190   bool is_smi() const { return kind_ == kSmi; }
should_access_heap() const191   bool should_access_heap() const {
192     return kind_ == kUnserializedHeapObject ||
193            kind_ == kNeverSerializedHeapObject ||
194            kind_ == kUnserializedReadOnlyHeapObject;
195   }
196 
197 #ifdef DEBUG
198   enum class Usage{kUnused, kOnlyIdentityUsed, kDataUsed};
199   mutable Usage used_status = Usage::kUnused;
200 #endif  // DEBUG
201 
202  private:
203   Handle<Object> const object_;
204   ObjectDataKind const kind_;
205 };
206 
207 class HeapObjectData : public ObjectData {
208  public:
209   HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
210                  Handle<HeapObject> object);
211 
boolean_value() const212   bool boolean_value() const { return boolean_value_; }
map() const213   ObjectData* map() const { return map_; }
214   InstanceType GetMapInstanceType() const;
215 
216   static HeapObjectData* Serialize(JSHeapBroker* broker,
217                                    Handle<HeapObject> object);
218 
219  private:
220   bool const boolean_value_;
221   ObjectData* const map_;
222 };
223 
224 class PropertyCellData : public HeapObjectData {
225  public:
226   PropertyCellData(JSHeapBroker* broker, ObjectData** storage,
227                    Handle<PropertyCell> object);
228 
property_details() const229   PropertyDetails property_details() const { return property_details_; }
230 
231   void Serialize(JSHeapBroker* broker);
value() const232   ObjectData* value() const { return value_; }
233 
234  private:
235   PropertyDetails const property_details_;
236 
237   ObjectData* value_ = nullptr;
238 };
239 
240 // TODO(mslekova): Once we have real-world usage data, we might want to
241 // reimplement this as sorted vector instead, to reduce the memory overhead.
242 typedef ZoneMap<ObjectData*, HolderLookupResult> KnownReceiversMap;
243 
244 class FunctionTemplateInfoData : public HeapObjectData {
245  public:
246   FunctionTemplateInfoData(JSHeapBroker* broker, ObjectData** storage,
247                            Handle<FunctionTemplateInfo> object);
248 
is_signature_undefined() const249   bool is_signature_undefined() const { return is_signature_undefined_; }
accept_any_receiver() const250   bool accept_any_receiver() const { return accept_any_receiver_; }
has_call_code() const251   bool has_call_code() const { return has_call_code_; }
252 
253   void SerializeCallCode(JSHeapBroker* broker);
call_code() const254   ObjectData* call_code() const { return call_code_; }
c_function() const255   Address c_function() const { return c_function_; }
c_signature() const256   const CFunctionInfo* c_signature() const { return c_signature_; }
known_receivers()257   KnownReceiversMap& known_receivers() { return known_receivers_; }
258 
259  private:
260   bool is_signature_undefined_ = false;
261   bool accept_any_receiver_ = false;
262   bool has_call_code_ = false;
263 
264   ObjectData* call_code_ = nullptr;
265   const Address c_function_;
266   const CFunctionInfo* const c_signature_;
267   KnownReceiversMap known_receivers_;
268 };
269 
270 class CallHandlerInfoData : public HeapObjectData {
271  public:
272   CallHandlerInfoData(JSHeapBroker* broker, ObjectData** storage,
273                       Handle<CallHandlerInfo> object);
274 
callback() const275   Address callback() const { return callback_; }
276 
277   void Serialize(JSHeapBroker* broker);
data() const278   ObjectData* data() const { return data_; }
279 
280  private:
281   Address const callback_;
282 
283   ObjectData* data_ = nullptr;
284 };
285 
FunctionTemplateInfoData(JSHeapBroker * broker,ObjectData ** storage,Handle<FunctionTemplateInfo> object)286 FunctionTemplateInfoData::FunctionTemplateInfoData(
287     JSHeapBroker* broker, ObjectData** storage,
288     Handle<FunctionTemplateInfo> object)
289     : HeapObjectData(broker, storage, object),
290       c_function_(v8::ToCData<Address>(object->GetCFunction())),
291       c_signature_(v8::ToCData<CFunctionInfo*>(object->GetCSignature())),
292       known_receivers_(broker->zone()) {
293   auto function_template_info = Handle<FunctionTemplateInfo>::cast(object);
294   is_signature_undefined_ =
295       function_template_info->signature().IsUndefined(broker->isolate());
296   accept_any_receiver_ = function_template_info->accept_any_receiver();
297 
298   CallOptimization call_optimization(broker->isolate(), object);
299   has_call_code_ = call_optimization.is_simple_api_call();
300 }
301 
CallHandlerInfoData(JSHeapBroker * broker,ObjectData ** storage,Handle<CallHandlerInfo> object)302 CallHandlerInfoData::CallHandlerInfoData(JSHeapBroker* broker,
303                                          ObjectData** storage,
304                                          Handle<CallHandlerInfo> object)
305     : HeapObjectData(broker, storage, object),
306       callback_(v8::ToCData<Address>(object->callback())) {
307   DCHECK(!FLAG_turbo_direct_heap_access);
308 }
309 
310 // These definitions are here in order to please the linker, which in debug mode
311 // sometimes requires static constants to be defined in .cc files.
312 const uint32_t JSHeapBroker::kMinimalRefsBucketCount;
313 const uint32_t JSHeapBroker::kInitialRefsBucketCount;
314 
IncrementTracingIndentation()315 void JSHeapBroker::IncrementTracingIndentation() { ++trace_indentation_; }
316 
DecrementTracingIndentation()317 void JSHeapBroker::DecrementTracingIndentation() { --trace_indentation_; }
318 
PropertyCellData(JSHeapBroker * broker,ObjectData ** storage,Handle<PropertyCell> object)319 PropertyCellData::PropertyCellData(JSHeapBroker* broker, ObjectData** storage,
320                                    Handle<PropertyCell> object)
321     : HeapObjectData(broker, storage, object),
322       property_details_(object->property_details()) {}
323 
Serialize(JSHeapBroker * broker)324 void PropertyCellData::Serialize(JSHeapBroker* broker) {
325   if (value_ != nullptr) return;
326 
327   TraceScope tracer(broker, this, "PropertyCellData::Serialize");
328   auto cell = Handle<PropertyCell>::cast(object());
329   value_ = broker->GetOrCreateData(cell->value());
330 }
331 
SerializeCallCode(JSHeapBroker * broker)332 void FunctionTemplateInfoData::SerializeCallCode(JSHeapBroker* broker) {
333   if (call_code_ != nullptr) return;
334 
335   TraceScope tracer(broker, this,
336                     "FunctionTemplateInfoData::SerializeCallCode");
337   auto function_template_info = Handle<FunctionTemplateInfo>::cast(object());
338   call_code_ =
339       broker->GetOrCreateData(function_template_info->call_code(kAcquireLoad));
340   if (call_code_->should_access_heap()) {
341     // TODO(mvstanton): When ObjectRef is in the never serialized list, this
342     // code can be removed.
343     broker->GetOrCreateData(
344         Handle<CallHandlerInfo>::cast(call_code_->object())->data());
345   } else {
346     call_code_->AsCallHandlerInfo()->Serialize(broker);
347   }
348 }
349 
Serialize(JSHeapBroker * broker)350 void CallHandlerInfoData::Serialize(JSHeapBroker* broker) {
351   if (data_ != nullptr) return;
352 
353   TraceScope tracer(broker, this, "CallHandlerInfoData::Serialize");
354   auto call_handler_info = Handle<CallHandlerInfo>::cast(object());
355   data_ = broker->GetOrCreateData(call_handler_info->data());
356 }
357 
358 class JSObjectField {
359  public:
IsDouble() const360   bool IsDouble() const { return object_ == nullptr; }
AsBitsOfDouble() const361   uint64_t AsBitsOfDouble() const {
362     CHECK(IsDouble());
363     return number_bits_;
364   }
AsDouble() const365   double AsDouble() const {
366     CHECK(IsDouble());
367     return bit_cast<double>(number_bits_);
368   }
369 
IsObject() const370   bool IsObject() const { return object_ != nullptr; }
AsObject() const371   ObjectData* AsObject() const {
372     CHECK(IsObject());
373     return object_;
374   }
375 
JSObjectField(uint64_t value_bits)376   explicit JSObjectField(uint64_t value_bits) : number_bits_(value_bits) {}
JSObjectField(ObjectData * value)377   explicit JSObjectField(ObjectData* value) : object_(value) {}
378 
379  private:
380   ObjectData* object_ = nullptr;
381   uint64_t number_bits_ = 0;
382 };
383 
384 class JSReceiverData : public HeapObjectData {
385  public:
JSReceiverData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSReceiver> object)386   JSReceiverData(JSHeapBroker* broker, ObjectData** storage,
387                  Handle<JSReceiver> object)
388       : HeapObjectData(broker, storage, object) {}
389 };
390 
391 class JSObjectData : public JSReceiverData {
392  public:
393   JSObjectData(JSHeapBroker* broker, ObjectData** storage,
394                Handle<JSObject> object);
395 
396   // Recursive serialization of all reachable JSObjects.
397   void SerializeAsBoilerplate(JSHeapBroker* broker);
398   const JSObjectField& GetInobjectField(int property_index) const;
399 
400   // Shallow serialization of {elements}.
401   void SerializeElements(JSHeapBroker* broker);
serialized_elements() const402   bool serialized_elements() const { return serialized_elements_; }
403   ObjectData* elements() const;
404 
405   void SerializeObjectCreateMap(JSHeapBroker* broker);
406 
object_create_map(JSHeapBroker * broker) const407   ObjectData* object_create_map(
408       JSHeapBroker* broker) const {  // Can be nullptr.
409     if (!serialized_object_create_map_) {
410       DCHECK_NULL(object_create_map_);
411       TRACE_MISSING(broker, "object_create_map on " << this);
412     }
413     return object_create_map_;
414   }
415 
416   ObjectData* GetOwnConstantElement(
417       JSHeapBroker* broker, uint32_t index,
418       SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
419   ObjectData* GetOwnDataProperty(
420       JSHeapBroker* broker, Representation representation,
421       FieldIndex field_index,
422       SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
423 
424   // This method is only used to assert our invariants.
425   bool cow_or_empty_elements_tenured() const;
426 
427  private:
428   void SerializeRecursiveAsBoilerplate(JSHeapBroker* broker, int max_depths);
429 
430   ObjectData* elements_ = nullptr;
431   bool cow_or_empty_elements_tenured_ = false;
432   // The {serialized_as_boilerplate} flag is set when all recursively
433   // reachable JSObjects are serialized.
434   bool serialized_as_boilerplate_ = false;
435   bool serialized_elements_ = false;
436 
437   ZoneVector<JSObjectField> inobject_fields_;
438 
439   bool serialized_object_create_map_ = false;
440   ObjectData* object_create_map_ = nullptr;
441 
442   // Elements (indexed properties) that either
443   // (1) are known to exist directly on the object as non-writable and
444   // non-configurable, or (2) are known not to (possibly they don't exist at
445   // all). In case (2), the second pair component is nullptr.
446   ZoneVector<std::pair<uint32_t, ObjectData*>> own_constant_elements_;
447   // Properties that either:
448   // (1) are known to exist directly on the object, or
449   // (2) are known not to (possibly they don't exist at all).
450   // In case (2), the second pair component is nullptr.
451   // For simplicity, this may in theory overlap with inobject_fields_.
452   // The keys of the map are the property_index() values of the
453   // respective property FieldIndex'es.
454   ZoneUnorderedMap<int, ObjectData*> own_properties_;
455 };
456 
SerializeObjectCreateMap(JSHeapBroker * broker)457 void JSObjectData::SerializeObjectCreateMap(JSHeapBroker* broker) {
458   if (serialized_object_create_map_) return;
459   serialized_object_create_map_ = true;
460 
461   TraceScope tracer(broker, this, "JSObjectData::SerializeObjectCreateMap");
462   Handle<JSObject> jsobject = Handle<JSObject>::cast(object());
463 
464   if (jsobject->map().is_prototype_map()) {
465     Handle<Object> maybe_proto_info(jsobject->map().prototype_info(),
466                                     broker->isolate());
467     if (maybe_proto_info->IsPrototypeInfo()) {
468       auto proto_info = Handle<PrototypeInfo>::cast(maybe_proto_info);
469       if (proto_info->HasObjectCreateMap()) {
470         DCHECK_NULL(object_create_map_);
471         object_create_map_ =
472             broker->GetOrCreateData(proto_info->ObjectCreateMap());
473       }
474     }
475   }
476 }
477 
478 namespace {
GetOwnElementFromHeap(JSHeapBroker * broker,Handle<Object> receiver,uint32_t index,bool constant_only)479 base::Optional<ObjectRef> GetOwnElementFromHeap(JSHeapBroker* broker,
480                                                 Handle<Object> receiver,
481                                                 uint32_t index,
482                                                 bool constant_only) {
483   LookupIterator it(broker->isolate(), receiver, index, LookupIterator::OWN);
484   if (it.state() == LookupIterator::DATA &&
485       (!constant_only || (it.IsReadOnly() && !it.IsConfigurable()))) {
486     return ObjectRef(broker,
487                      broker->CanonicalPersistentHandle(it.GetDataValue()));
488   }
489   return base::nullopt;
490 }
491 
GetOwnDataPropertyFromHeap(JSHeapBroker * broker,Handle<JSObject> receiver,Representation representation,FieldIndex field_index)492 ObjectRef GetOwnDataPropertyFromHeap(JSHeapBroker* broker,
493                                      Handle<JSObject> receiver,
494                                      Representation representation,
495                                      FieldIndex field_index) {
496   Handle<Object> constant =
497       JSObject::FastPropertyAt(receiver, representation, field_index);
498   return ObjectRef(broker, constant);
499 }
500 
501 }  // namespace
502 
GetOwnConstantElement(JSHeapBroker * broker,uint32_t index,SerializationPolicy policy)503 ObjectData* JSObjectData::GetOwnConstantElement(JSHeapBroker* broker,
504                                                 uint32_t index,
505                                                 SerializationPolicy policy) {
506   for (auto const& p : own_constant_elements_) {
507     if (p.first == index) return p.second;
508   }
509 
510   if (policy == SerializationPolicy::kAssumeSerialized) {
511     TRACE_MISSING(broker, "knowledge about index " << index << " on " << this);
512     return nullptr;
513   }
514 
515   base::Optional<ObjectRef> element =
516       GetOwnElementFromHeap(broker, object(), index, true);
517   ObjectData* result = element.has_value() ? element->data() : nullptr;
518   own_constant_elements_.push_back({index, result});
519   return result;
520 }
521 
GetOwnDataProperty(JSHeapBroker * broker,Representation representation,FieldIndex field_index,SerializationPolicy policy)522 ObjectData* JSObjectData::GetOwnDataProperty(JSHeapBroker* broker,
523                                              Representation representation,
524                                              FieldIndex field_index,
525                                              SerializationPolicy policy) {
526   auto p = own_properties_.find(field_index.property_index());
527   if (p != own_properties_.end()) return p->second;
528 
529   if (policy == SerializationPolicy::kAssumeSerialized) {
530     TRACE_MISSING(broker, "knowledge about property with index "
531                               << field_index.property_index() << " on "
532                               << this);
533     return nullptr;
534   }
535 
536   ObjectRef property = GetOwnDataPropertyFromHeap(
537       broker, Handle<JSObject>::cast(object()), representation, field_index);
538   ObjectData* result(property.data());
539   own_properties_.insert(std::make_pair(field_index.property_index(), result));
540   return result;
541 }
542 
543 class JSTypedArrayData : public JSObjectData {
544  public:
545   JSTypedArrayData(JSHeapBroker* broker, ObjectData** storage,
546                    Handle<JSTypedArray> object);
547 
is_on_heap() const548   bool is_on_heap() const { return is_on_heap_; }
length() const549   size_t length() const { return length_; }
data_ptr() const550   void* data_ptr() const { return data_ptr_; }
551 
552   void Serialize(JSHeapBroker* broker);
serialized() const553   bool serialized() const { return serialized_; }
554 
buffer() const555   ObjectData* buffer() const { return buffer_; }
556 
557  private:
558   bool const is_on_heap_;
559   size_t const length_;
560   void* const data_ptr_;
561 
562   bool serialized_ = false;
563   ObjectData* buffer_ = nullptr;
564 };
565 
JSTypedArrayData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSTypedArray> object)566 JSTypedArrayData::JSTypedArrayData(JSHeapBroker* broker, ObjectData** storage,
567                                    Handle<JSTypedArray> object)
568     : JSObjectData(broker, storage, object),
569       is_on_heap_(object->is_on_heap()),
570       length_(object->length()),
571       data_ptr_(object->DataPtr()) {}
572 
Serialize(JSHeapBroker * broker)573 void JSTypedArrayData::Serialize(JSHeapBroker* broker) {
574   if (serialized_) return;
575   serialized_ = true;
576 
577   TraceScope tracer(broker, this, "JSTypedArrayData::Serialize");
578   Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object());
579 
580   if (!is_on_heap()) {
581     DCHECK_NULL(buffer_);
582     buffer_ = broker->GetOrCreateData(typed_array->buffer());
583   }
584 }
585 
586 class ArrayBoilerplateDescriptionData : public HeapObjectData {
587  public:
ArrayBoilerplateDescriptionData(JSHeapBroker * broker,ObjectData ** storage,Handle<ArrayBoilerplateDescription> object)588   ArrayBoilerplateDescriptionData(JSHeapBroker* broker, ObjectData** storage,
589                                   Handle<ArrayBoilerplateDescription> object)
590       : HeapObjectData(broker, storage, object),
591         constants_elements_length_(object->constant_elements().length()) {
592     DCHECK(!FLAG_turbo_direct_heap_access);
593   }
594 
constants_elements_length() const595   int constants_elements_length() const { return constants_elements_length_; }
596 
597  private:
598   int const constants_elements_length_;
599 };
600 
601 class ObjectBoilerplateDescriptionData : public HeapObjectData {
602  public:
ObjectBoilerplateDescriptionData(JSHeapBroker * broker,ObjectData ** storage,Handle<ObjectBoilerplateDescription> object)603   ObjectBoilerplateDescriptionData(JSHeapBroker* broker, ObjectData** storage,
604                                    Handle<ObjectBoilerplateDescription> object)
605       : HeapObjectData(broker, storage, object), size_(object->size()) {
606     DCHECK(!FLAG_turbo_direct_heap_access);
607   }
608 
size() const609   int size() const { return size_; }
610 
611  private:
612   int const size_;
613 };
614 
615 class JSDataViewData : public JSObjectData {
616  public:
617   JSDataViewData(JSHeapBroker* broker, ObjectData** storage,
618                  Handle<JSDataView> object);
619 
byte_length() const620   size_t byte_length() const { return byte_length_; }
621 
622  private:
623   size_t const byte_length_;
624 };
625 
626 class JSBoundFunctionData : public JSObjectData {
627  public:
628   JSBoundFunctionData(JSHeapBroker* broker, ObjectData** storage,
629                       Handle<JSBoundFunction> object);
630 
631   bool Serialize(JSHeapBroker* broker);
serialized() const632   bool serialized() const { return serialized_; }
633 
bound_target_function() const634   ObjectData* bound_target_function() const { return bound_target_function_; }
bound_this() const635   ObjectData* bound_this() const { return bound_this_; }
bound_arguments() const636   ObjectData* bound_arguments() const { return bound_arguments_; }
637 
638  private:
639   bool serialized_ = false;
640 
641   ObjectData* bound_target_function_ = nullptr;
642   ObjectData* bound_this_ = nullptr;
643   ObjectData* bound_arguments_ = nullptr;
644 };
645 
646 class JSFunctionData : public JSObjectData {
647  public:
648   JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
649                  Handle<JSFunction> object);
650 
has_feedback_vector() const651   bool has_feedback_vector() const { return has_feedback_vector_; }
has_initial_map() const652   bool has_initial_map() const { return has_initial_map_; }
has_prototype() const653   bool has_prototype() const { return has_prototype_; }
HasAttachedOptimizedCode() const654   bool HasAttachedOptimizedCode() const { return has_attached_optimized_code_; }
PrototypeRequiresRuntimeLookup() const655   bool PrototypeRequiresRuntimeLookup() const {
656     return PrototypeRequiresRuntimeLookup_;
657   }
658 
659   void Serialize(JSHeapBroker* broker);
serialized() const660   bool serialized() const { return serialized_; }
661 
context() const662   ObjectData* context() const { return context_; }
native_context() const663   ObjectData* native_context() const { return native_context_; }
initial_map() const664   ObjectData* initial_map() const { return initial_map_; }
prototype() const665   ObjectData* prototype() const { return prototype_; }
shared() const666   ObjectData* shared() const { return shared_; }
raw_feedback_cell() const667   ObjectData* raw_feedback_cell() const { return feedback_cell_; }
feedback_vector() const668   ObjectData* feedback_vector() const { return feedback_vector_; }
code() const669   ObjectData* code() const { return code_; }
initial_map_instance_size_with_min_slack() const670   int initial_map_instance_size_with_min_slack() const {
671     CHECK(serialized_);
672     return initial_map_instance_size_with_min_slack_;
673   }
674 
675  private:
676   bool has_feedback_vector_;
677   bool has_initial_map_;
678   bool has_prototype_;
679   bool has_attached_optimized_code_;
680   bool PrototypeRequiresRuntimeLookup_;
681 
682   bool serialized_ = false;
683 
684   ObjectData* context_ = nullptr;
685   ObjectData* native_context_ = nullptr;
686   ObjectData* initial_map_ = nullptr;
687   ObjectData* prototype_ = nullptr;
688   ObjectData* shared_ = nullptr;
689   ObjectData* feedback_vector_ = nullptr;
690   ObjectData* feedback_cell_ = nullptr;
691   ObjectData* code_ = nullptr;
692   int initial_map_instance_size_with_min_slack_;
693 };
694 
695 class JSRegExpData : public JSObjectData {
696  public:
JSRegExpData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSRegExp> object)697   JSRegExpData(JSHeapBroker* broker, ObjectData** storage,
698                Handle<JSRegExp> object)
699       : JSObjectData(broker, storage, object) {}
700 
701   void SerializeAsRegExpBoilerplate(JSHeapBroker* broker);
702 
raw_properties_or_hash() const703   ObjectData* raw_properties_or_hash() const { return raw_properties_or_hash_; }
data() const704   ObjectData* data() const { return data_; }
source() const705   ObjectData* source() const { return source_; }
flags() const706   ObjectData* flags() const { return flags_; }
last_index() const707   ObjectData* last_index() const { return last_index_; }
708 
709  private:
710   bool serialized_as_reg_exp_boilerplate_ = false;
711 
712   ObjectData* raw_properties_or_hash_ = nullptr;
713   ObjectData* data_ = nullptr;
714   ObjectData* source_ = nullptr;
715   ObjectData* flags_ = nullptr;
716   ObjectData* last_index_ = nullptr;
717 };
718 
719 class HeapNumberData : public HeapObjectData {
720  public:
HeapNumberData(JSHeapBroker * broker,ObjectData ** storage,Handle<HeapNumber> object)721   HeapNumberData(JSHeapBroker* broker, ObjectData** storage,
722                  Handle<HeapNumber> object)
723       : HeapObjectData(broker, storage, object), value_(object->value()) {
724   }
725 
value() const726   double value() const { return value_; }
727 
728  private:
729   double const value_;
730 };
731 
732 class ContextData : public HeapObjectData {
733  public:
734   ContextData(JSHeapBroker* broker, ObjectData** storage,
735               Handle<Context> object);
736 
737   ObjectData* previous(
738       JSHeapBroker* broker,
739       SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
740 
741   // Returns nullptr if the slot index isn't valid or wasn't serialized,
742   // unless {policy} is {kSerializeIfNeeded}.
743   ObjectData* GetSlot(
744       JSHeapBroker* broker, int index,
745       SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
746 
747  private:
748   ZoneMap<int, ObjectData*> slots_;
749   ObjectData* previous_ = nullptr;
750 };
751 
ContextData(JSHeapBroker * broker,ObjectData ** storage,Handle<Context> object)752 ContextData::ContextData(JSHeapBroker* broker, ObjectData** storage,
753                          Handle<Context> object)
754     : HeapObjectData(broker, storage, object), slots_(broker->zone()) {}
755 
previous(JSHeapBroker * broker,SerializationPolicy policy)756 ObjectData* ContextData::previous(JSHeapBroker* broker,
757                                   SerializationPolicy policy) {
758   if (policy == SerializationPolicy::kSerializeIfNeeded &&
759       previous_ == nullptr) {
760     TraceScope tracer(broker, this, "ContextData::previous");
761     Handle<Context> context = Handle<Context>::cast(object());
762     previous_ = broker->GetOrCreateData(context->unchecked_previous());
763   }
764   return previous_;
765 }
766 
GetSlot(JSHeapBroker * broker,int index,SerializationPolicy policy)767 ObjectData* ContextData::GetSlot(JSHeapBroker* broker, int index,
768                                  SerializationPolicy policy) {
769   CHECK_GE(index, 0);
770   auto search = slots_.find(index);
771   if (search != slots_.end()) {
772     return search->second;
773   }
774 
775   if (policy == SerializationPolicy::kSerializeIfNeeded) {
776     Handle<Context> context = Handle<Context>::cast(object());
777     if (index < context->length()) {
778       TraceScope tracer(broker, this, "ContextData::GetSlot");
779       TRACE(broker, "Serializing context slot " << index);
780       ObjectData* odata = broker->GetOrCreateData(context->get(index));
781       slots_.insert(std::make_pair(index, odata));
782       return odata;
783     }
784   }
785 
786   return nullptr;
787 }
788 
789 class NativeContextData : public ContextData {
790  public:
791 #define DECL_ACCESSOR(type, name) \
792   ObjectData* name() const { return name##_; }
BROKER_NATIVE_CONTEXT_FIELDS(DECL_ACCESSOR) const793   BROKER_NATIVE_CONTEXT_FIELDS(DECL_ACCESSOR)
794 #undef DECL_ACCESSOR
795 
796   const ZoneVector<ObjectData*>& function_maps() const {
797     CHECK(serialized_);
798     return function_maps_;
799   }
800 
scope_info() const801   ObjectData* scope_info() const {
802     CHECK(serialized_);
803     return scope_info_;
804   }
805 
806   NativeContextData(JSHeapBroker* broker, ObjectData** storage,
807                     Handle<NativeContext> object);
808   void Serialize(JSHeapBroker* broker);
809 
810  private:
811   bool serialized_ = false;
812 #define DECL_MEMBER(type, name) ObjectData* name##_ = nullptr;
813   BROKER_NATIVE_CONTEXT_FIELDS(DECL_MEMBER)
814 #undef DECL_MEMBER
815   ZoneVector<ObjectData*> function_maps_;
816   ObjectData* scope_info_ = nullptr;
817 };
818 
819 class NameData : public HeapObjectData {
820  public:
NameData(JSHeapBroker * broker,ObjectData ** storage,Handle<Name> object)821   NameData(JSHeapBroker* broker, ObjectData** storage, Handle<Name> object)
822       : HeapObjectData(broker, storage, object) {}
823 };
824 
825 class StringData : public NameData {
826  public:
827   StringData(JSHeapBroker* broker, ObjectData** storage, Handle<String> object);
828 
length() const829   int length() const { return length_; }
first_char() const830   uint16_t first_char() const { return first_char_; }
to_number() const831   base::Optional<double> to_number() const { return to_number_; }
is_external_string() const832   bool is_external_string() const { return is_external_string_; }
is_seq_string() const833   bool is_seq_string() const { return is_seq_string_; }
834 
835   ObjectData* GetCharAsString(
836       JSHeapBroker* broker, uint32_t index,
837       SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
838 
839  private:
840   int const length_;
841   uint16_t const first_char_;
842   base::Optional<double> to_number_;
843   bool const is_external_string_;
844   bool const is_seq_string_;
845 
846   // Known individual characters as strings, corresponding to the semantics of
847   // element access (s[i]). The first pair component is always less than
848   // {length_}. The second component is never nullptr.
849   ZoneVector<std::pair<uint32_t, ObjectData*>> chars_as_strings_;
850 };
851 
852 class SymbolData : public NameData {
853  public:
SymbolData(JSHeapBroker * broker,ObjectData ** storage,Handle<Symbol> object)854   SymbolData(JSHeapBroker* broker, ObjectData** storage, Handle<Symbol> object)
855       : NameData(broker, storage, object) {
856     DCHECK(!FLAG_turbo_direct_heap_access);
857   }
858 };
859 
860 namespace {
861 
862 // String to double helper without heap allocation.
StringToDouble(Handle<String> object)863 base::Optional<double> StringToDouble(Handle<String> object) {
864   const int kMaxLengthForDoubleConversion = 23;
865   String string = *object;
866   int length = string.length();
867   if (length <= kMaxLengthForDoubleConversion) {
868     const int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
869     uc16 buffer[kMaxLengthForDoubleConversion];
870     String::WriteToFlat(*object, buffer, 0, length);
871     Vector<const uc16> v(buffer, length);
872     return StringToDouble(v, flags);
873   }
874   return base::nullopt;
875 }
876 
877 }  // namespace
878 
StringData(JSHeapBroker * broker,ObjectData ** storage,Handle<String> object)879 StringData::StringData(JSHeapBroker* broker, ObjectData** storage,
880                        Handle<String> object)
881     : NameData(broker, storage, object),
882       length_(object->length()),
883       first_char_(length_ > 0 ? object->Get(0) : 0),
884       to_number_(StringToDouble(object)),
885       is_external_string_(object->IsExternalString()),
886       is_seq_string_(object->IsSeqString()),
887       chars_as_strings_(broker->zone()) {}
888 
889 class InternalizedStringData : public StringData {
890  public:
891   InternalizedStringData(JSHeapBroker* broker, ObjectData** storage,
892                          Handle<InternalizedString> object);
893 
array_index() const894   uint32_t array_index() const { return array_index_; }
895 
896  private:
897   uint32_t array_index_;
898 };
899 
GetCharAsString(JSHeapBroker * broker,uint32_t index,SerializationPolicy policy)900 ObjectData* StringData::GetCharAsString(JSHeapBroker* broker, uint32_t index,
901                                         SerializationPolicy policy) {
902   if (index >= static_cast<uint32_t>(length())) return nullptr;
903 
904   for (auto const& p : chars_as_strings_) {
905     if (p.first == index) return p.second;
906   }
907 
908   if (policy == SerializationPolicy::kAssumeSerialized) {
909     TRACE_MISSING(broker, "knowledge about index " << index << " on " << this);
910     return nullptr;
911   }
912 
913   base::Optional<ObjectRef> element =
914       GetOwnElementFromHeap(broker, object(), index, true);
915   ObjectData* result = element.has_value() ? element->data() : nullptr;
916   chars_as_strings_.push_back({index, result});
917   return result;
918 }
919 
InternalizedStringData(JSHeapBroker * broker,ObjectData ** storage,Handle<InternalizedString> object)920 InternalizedStringData::InternalizedStringData(
921     JSHeapBroker* broker, ObjectData** storage,
922     Handle<InternalizedString> object)
923     : StringData(broker, storage, object) {}
924 
925 namespace {
926 
IsFastLiteralHelper(Handle<JSObject> boilerplate,int max_depth,int * max_properties)927 bool IsFastLiteralHelper(Handle<JSObject> boilerplate, int max_depth,
928                          int* max_properties) {
929   DCHECK_GE(max_depth, 0);
930   DCHECK_GE(*max_properties, 0);
931 
932   Isolate* const isolate = boilerplate->GetIsolate();
933 
934   // Make sure the boilerplate map is not deprecated.
935   if (!JSObject::TryMigrateInstance(isolate, boilerplate)) return false;
936 
937   // Check for too deep nesting.
938   if (max_depth == 0) return false;
939 
940   // Check the elements.
941   Handle<FixedArrayBase> elements(boilerplate->elements(), isolate);
942   if (elements->length() > 0 &&
943       elements->map() != ReadOnlyRoots(isolate).fixed_cow_array_map()) {
944     if (boilerplate->HasSmiOrObjectElements()) {
945       Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
946       int length = elements->length();
947       for (int i = 0; i < length; i++) {
948         if ((*max_properties)-- == 0) return false;
949         Handle<Object> value(fast_elements->get(i), isolate);
950         if (value->IsJSObject()) {
951           Handle<JSObject> value_object = Handle<JSObject>::cast(value);
952           if (!IsFastLiteralHelper(value_object, max_depth - 1,
953                                    max_properties)) {
954             return false;
955           }
956         }
957       }
958     } else if (boilerplate->HasDoubleElements()) {
959       if (elements->Size() > kMaxRegularHeapObjectSize) return false;
960     } else {
961       return false;
962     }
963   }
964 
965   // TODO(turbofan): Do we want to support out-of-object properties?
966   if (!(boilerplate->HasFastProperties() &&
967         boilerplate->property_array().length() == 0)) {
968     return false;
969   }
970 
971   // Check the in-object properties.
972   Handle<DescriptorArray> descriptors(
973       boilerplate->map().instance_descriptors(kRelaxedLoad), isolate);
974   for (InternalIndex i : boilerplate->map().IterateOwnDescriptors()) {
975     PropertyDetails details = descriptors->GetDetails(i);
976     if (details.location() != kField) continue;
977     DCHECK_EQ(kData, details.kind());
978     if ((*max_properties)-- == 0) return false;
979     FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
980     if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
981     Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), isolate);
982     if (value->IsJSObject()) {
983       Handle<JSObject> value_object = Handle<JSObject>::cast(value);
984       if (!IsFastLiteralHelper(value_object, max_depth - 1, max_properties)) {
985         return false;
986       }
987     }
988   }
989   return true;
990 }
991 
992 // Maximum depth and total number of elements and properties for literal
993 // graphs to be considered for fast deep-copying. The limit is chosen to
994 // match the maximum number of inobject properties, to ensure that the
995 // performance of using object literals is not worse than using constructor
996 // functions, see crbug.com/v8/6211 for details.
997 const int kMaxFastLiteralDepth = 3;
998 const int kMaxFastLiteralProperties = JSObject::kMaxInObjectProperties;
999 
1000 // Determines whether the given array or object literal boilerplate satisfies
1001 // all limits to be considered for fast deep-copying and computes the total
1002 // size of all objects that are part of the graph.
IsInlinableFastLiteral(Handle<JSObject> boilerplate)1003 bool IsInlinableFastLiteral(Handle<JSObject> boilerplate) {
1004   int max_properties = kMaxFastLiteralProperties;
1005   return IsFastLiteralHelper(boilerplate, kMaxFastLiteralDepth,
1006                              &max_properties);
1007 }
1008 
1009 }  // namespace
1010 
1011 class AccessorInfoData : public HeapObjectData {
1012  public:
1013   AccessorInfoData(JSHeapBroker* broker, ObjectData** storage,
1014                    Handle<AccessorInfo> object);
1015 };
1016 
1017 class AllocationSiteData : public HeapObjectData {
1018  public:
1019   AllocationSiteData(JSHeapBroker* broker, ObjectData** storage,
1020                      Handle<AllocationSite> object);
1021   void SerializeBoilerplate(JSHeapBroker* broker);
1022 
PointsToLiteral() const1023   bool PointsToLiteral() const { return PointsToLiteral_; }
GetAllocationType() const1024   AllocationType GetAllocationType() const { return GetAllocationType_; }
nested_site() const1025   ObjectData* nested_site() const { return nested_site_; }
IsFastLiteral() const1026   bool IsFastLiteral() const { return IsFastLiteral_; }
boilerplate() const1027   ObjectData* boilerplate() const { return boilerplate_; }
1028 
1029   // These are only valid if PointsToLiteral is false.
GetElementsKind() const1030   ElementsKind GetElementsKind() const { return GetElementsKind_; }
CanInlineCall() const1031   bool CanInlineCall() const { return CanInlineCall_; }
1032 
1033  private:
1034   bool const PointsToLiteral_;
1035   AllocationType const GetAllocationType_;
1036   ObjectData* nested_site_ = nullptr;
1037   bool IsFastLiteral_ = false;
1038   ObjectData* boilerplate_ = nullptr;
1039   ElementsKind GetElementsKind_ = NO_ELEMENTS;
1040   bool CanInlineCall_ = false;
1041   bool serialized_boilerplate_ = false;
1042 };
1043 
1044 class BigIntData : public HeapObjectData {
1045  public:
BigIntData(JSHeapBroker * broker,ObjectData ** storage,Handle<BigInt> object)1046   BigIntData(JSHeapBroker* broker, ObjectData** storage, Handle<BigInt> object)
1047       : HeapObjectData(broker, storage, object),
1048         as_uint64_(object->AsUint64(nullptr)) {
1049   }
1050 
AsUint64() const1051   uint64_t AsUint64() const { return as_uint64_; }
1052 
1053  private:
1054   const uint64_t as_uint64_;
1055 };
1056 
1057 // Only used in JSNativeContextSpecialization.
1058 class ScriptContextTableData : public HeapObjectData {
1059  public:
ScriptContextTableData(JSHeapBroker * broker,ObjectData ** storage,Handle<ScriptContextTable> object)1060   ScriptContextTableData(JSHeapBroker* broker, ObjectData** storage,
1061                          Handle<ScriptContextTable> object)
1062       : HeapObjectData(broker, storage, object) {}
1063 };
1064 
1065 struct PropertyDescriptor {
1066   ObjectData* key = nullptr;
1067   ObjectData* value = nullptr;
1068   PropertyDetails details = PropertyDetails::Empty();
1069   FieldIndex field_index;
1070   ObjectData* field_owner = nullptr;
1071   ObjectData* field_type = nullptr;
1072   bool is_unboxed_double_field = false;
1073 };
1074 
1075 class MapData : public HeapObjectData {
1076  public:
1077   MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object);
1078 
instance_type() const1079   InstanceType instance_type() const { return instance_type_; }
instance_size() const1080   int instance_size() const { return instance_size_; }
bit_field() const1081   byte bit_field() const { return bit_field_; }
bit_field2() const1082   byte bit_field2() const { return bit_field2_; }
bit_field3() const1083   uint32_t bit_field3() const { return bit_field3_; }
can_be_deprecated() const1084   bool can_be_deprecated() const { return can_be_deprecated_; }
can_transition() const1085   bool can_transition() const { return can_transition_; }
in_object_properties_start_in_words() const1086   int in_object_properties_start_in_words() const {
1087     CHECK(InstanceTypeChecker::IsJSObject(instance_type()));
1088     return in_object_properties_start_in_words_;
1089   }
in_object_properties() const1090   int in_object_properties() const {
1091     CHECK(InstanceTypeChecker::IsJSObject(instance_type()));
1092     return in_object_properties_;
1093   }
constructor_function_index() const1094   int constructor_function_index() const { return constructor_function_index_; }
NextFreePropertyIndex() const1095   int NextFreePropertyIndex() const { return next_free_property_index_; }
UnusedPropertyFields() const1096   int UnusedPropertyFields() const { return unused_property_fields_; }
supports_fast_array_iteration() const1097   bool supports_fast_array_iteration() const {
1098     return supports_fast_array_iteration_;
1099   }
supports_fast_array_resize() const1100   bool supports_fast_array_resize() const {
1101     return supports_fast_array_resize_;
1102   }
is_abandoned_prototype_map() const1103   bool is_abandoned_prototype_map() const {
1104     return is_abandoned_prototype_map_;
1105   }
1106 
1107   // Extra information.
1108 
1109   void SerializeElementsKindGeneralizations(JSHeapBroker* broker);
elements_kind_generalizations() const1110   const ZoneVector<ObjectData*>& elements_kind_generalizations() const {
1111     CHECK(serialized_elements_kind_generalizations_);
1112     return elements_kind_generalizations_;
1113   }
1114 
1115   // Serialize a single (or all) own slot(s) of the descriptor array and recurse
1116   // on field owner(s).
1117   void SerializeOwnDescriptor(JSHeapBroker* broker,
1118                               InternalIndex descriptor_index);
1119   void SerializeOwnDescriptors(JSHeapBroker* broker);
1120   ObjectData* GetStrongValue(InternalIndex descriptor_index) const;
1121   // TODO(neis): This code needs to be changed to allow for ObjectData* instance
1122   // descriptors. However, this is likely to require a non-trivial refactoring
1123   // of how maps are serialized because actual instance descriptors don't
1124   // contain information about owner maps.
instance_descriptors() const1125   DescriptorArrayData* instance_descriptors() const {
1126     return instance_descriptors_;
1127   }
1128 
1129   void SerializeRootMap(JSHeapBroker* broker);
1130   ObjectData* FindRootMap() const;
1131 
1132   void SerializeConstructor(JSHeapBroker* broker);
GetConstructor() const1133   ObjectData* GetConstructor() const {
1134     CHECK(serialized_constructor_);
1135     return constructor_;
1136   }
1137 
1138   void SerializeBackPointer(JSHeapBroker* broker);
GetBackPointer() const1139   ObjectData* GetBackPointer() const {
1140     CHECK(serialized_backpointer_);
1141     return backpointer_;
1142   }
1143 
1144   void SerializePrototype(JSHeapBroker* broker);
serialized_prototype() const1145   bool serialized_prototype() const { return serialized_prototype_; }
prototype() const1146   ObjectData* prototype() const {
1147     CHECK(serialized_prototype_);
1148     return prototype_;
1149   }
1150 
1151   void SerializeForElementLoad(JSHeapBroker* broker);
1152 
1153   void SerializeForElementStore(JSHeapBroker* broker);
1154 
1155  private:
1156   InstanceType const instance_type_;
1157   int const instance_size_;
1158   byte const bit_field_;
1159   byte const bit_field2_;
1160   uint32_t const bit_field3_;
1161   bool const can_be_deprecated_;
1162   bool const can_transition_;
1163   int const in_object_properties_start_in_words_;
1164   int const in_object_properties_;
1165   int const constructor_function_index_;
1166   int const next_free_property_index_;
1167   int const unused_property_fields_;
1168   bool const supports_fast_array_iteration_;
1169   bool const supports_fast_array_resize_;
1170   bool const is_abandoned_prototype_map_;
1171 
1172   bool serialized_elements_kind_generalizations_ = false;
1173   ZoneVector<ObjectData*> elements_kind_generalizations_;
1174 
1175   bool serialized_own_descriptors_ = false;
1176   DescriptorArrayData* instance_descriptors_ = nullptr;
1177 
1178   bool serialized_constructor_ = false;
1179   ObjectData* constructor_ = nullptr;
1180 
1181   bool serialized_backpointer_ = false;
1182   ObjectData* backpointer_ = nullptr;
1183 
1184   bool serialized_prototype_ = false;
1185   ObjectData* prototype_ = nullptr;
1186 
1187   bool serialized_root_map_ = false;
1188   ObjectData* root_map_ = nullptr;
1189 
1190   bool serialized_for_element_load_ = false;
1191 
1192   bool serialized_for_element_store_ = false;
1193 };
1194 
AccessorInfoData(JSHeapBroker * broker,ObjectData ** storage,Handle<AccessorInfo> object)1195 AccessorInfoData::AccessorInfoData(JSHeapBroker* broker, ObjectData** storage,
1196                                    Handle<AccessorInfo> object)
1197     : HeapObjectData(broker, storage, object) {
1198   DCHECK(!FLAG_turbo_direct_heap_access);
1199 }
1200 
AllocationSiteData(JSHeapBroker * broker,ObjectData ** storage,Handle<AllocationSite> object)1201 AllocationSiteData::AllocationSiteData(JSHeapBroker* broker,
1202                                        ObjectData** storage,
1203                                        Handle<AllocationSite> object)
1204     : HeapObjectData(broker, storage, object),
1205       PointsToLiteral_(object->PointsToLiteral()),
1206       GetAllocationType_(object->GetAllocationType()) {
1207   if (PointsToLiteral_) {
1208     IsFastLiteral_ = IsInlinableFastLiteral(
1209         handle(object->boilerplate(), broker->isolate()));
1210   } else {
1211     GetElementsKind_ = object->GetElementsKind();
1212     CanInlineCall_ = object->CanInlineCall();
1213   }
1214 }
1215 
SerializeBoilerplate(JSHeapBroker * broker)1216 void AllocationSiteData::SerializeBoilerplate(JSHeapBroker* broker) {
1217   if (serialized_boilerplate_) return;
1218   serialized_boilerplate_ = true;
1219 
1220   TraceScope tracer(broker, this, "AllocationSiteData::SerializeBoilerplate");
1221   Handle<AllocationSite> site = Handle<AllocationSite>::cast(object());
1222 
1223   CHECK(IsFastLiteral_);
1224   DCHECK_NULL(boilerplate_);
1225   boilerplate_ = broker->GetOrCreateData(site->boilerplate());
1226   if (!boilerplate_->should_access_heap()) {
1227     boilerplate_->AsJSObject()->SerializeAsBoilerplate(broker);
1228   }
1229 
1230   DCHECK_NULL(nested_site_);
1231   nested_site_ = broker->GetOrCreateData(site->nested_site());
1232   if (nested_site_->IsAllocationSite() && !nested_site_->should_access_heap()) {
1233     nested_site_->AsAllocationSite()->SerializeBoilerplate(broker);
1234   }
1235 }
1236 
HeapObjectData(JSHeapBroker * broker,ObjectData ** storage,Handle<HeapObject> object)1237 HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
1238                                Handle<HeapObject> object)
1239     : ObjectData(broker, storage, object, kSerializedHeapObject),
1240       boolean_value_(object->BooleanValue(broker->isolate())),
1241       // We have to use a raw cast below instead of AsMap() because of
1242       // recursion. AsMap() would call IsMap(), which accesses the
1243       // instance_type_ member. In the case of constructing the MapData for the
1244       // meta map (whose map is itself), this member has not yet been
1245       // initialized.
1246       map_(broker->GetOrCreateData(object->map())) {
1247   CHECK_EQ(broker->mode(), JSHeapBroker::kSerializing);
1248 }
1249 
GetMapInstanceType() const1250 InstanceType HeapObjectData::GetMapInstanceType() const {
1251   ObjectData* map_data = map();
1252   if (map_data->should_access_heap()) {
1253     AllowHandleDereferenceIfNeeded allow_handle_dereference(kind());
1254     return Handle<Map>::cast(map_data->object())->instance_type();
1255   }
1256   return map_data->AsMap()->instance_type();
1257 }
1258 
1259 namespace {
IsReadOnlyLengthDescriptor(Isolate * isolate,Handle<Map> jsarray_map)1260 bool IsReadOnlyLengthDescriptor(Isolate* isolate, Handle<Map> jsarray_map) {
1261   DCHECK(!jsarray_map->is_dictionary_map());
1262   Handle<Name> length_string = isolate->factory()->length_string();
1263   DescriptorArray descriptors = jsarray_map->instance_descriptors(kRelaxedLoad);
1264   // TODO(jkummerow): We could skip the search and hardcode number == 0.
1265   InternalIndex number = descriptors.Search(*length_string, *jsarray_map);
1266   DCHECK(number.is_found());
1267   return descriptors.GetDetails(number).IsReadOnly();
1268 }
1269 
SupportsFastArrayIteration(Isolate * isolate,Handle<Map> map)1270 bool SupportsFastArrayIteration(Isolate* isolate, Handle<Map> map) {
1271   return map->instance_type() == JS_ARRAY_TYPE &&
1272          IsFastElementsKind(map->elements_kind()) &&
1273          map->prototype().IsJSArray() &&
1274          isolate->IsAnyInitialArrayPrototype(
1275              handle(JSArray::cast(map->prototype()), isolate)) &&
1276          Protectors::IsNoElementsIntact(isolate);
1277 }
1278 
SupportsFastArrayResize(Isolate * isolate,Handle<Map> map)1279 bool SupportsFastArrayResize(Isolate* isolate, Handle<Map> map) {
1280   return SupportsFastArrayIteration(isolate, map) && map->is_extensible() &&
1281          !map->is_dictionary_map() && !IsReadOnlyLengthDescriptor(isolate, map);
1282 }
1283 }  // namespace
1284 
MapData(JSHeapBroker * broker,ObjectData ** storage,Handle<Map> object)1285 MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object)
1286     : HeapObjectData(broker, storage, object),
1287       instance_type_(object->instance_type()),
1288       instance_size_(object->instance_size()),
1289       bit_field_(object->bit_field()),
1290       bit_field2_(object->bit_field2()),
1291       bit_field3_(object->bit_field3()),
1292       can_be_deprecated_(object->NumberOfOwnDescriptors() > 0
1293                              ? object->CanBeDeprecated()
1294                              : false),
1295       can_transition_(object->CanTransition()),
1296       in_object_properties_start_in_words_(
1297           object->IsJSObjectMap() ? object->GetInObjectPropertiesStartInWords()
1298                                   : 0),
1299       in_object_properties_(
1300           object->IsJSObjectMap() ? object->GetInObjectProperties() : 0),
1301       constructor_function_index_(object->IsPrimitiveMap()
1302                                       ? object->GetConstructorFunctionIndex()
1303                                       : Map::kNoConstructorFunctionIndex),
1304       next_free_property_index_(object->NextFreePropertyIndex()),
1305       unused_property_fields_(object->UnusedPropertyFields()),
1306       supports_fast_array_iteration_(
1307           SupportsFastArrayIteration(broker->isolate(), object)),
1308       supports_fast_array_resize_(
1309           SupportsFastArrayResize(broker->isolate(), object)),
1310       is_abandoned_prototype_map_(object->is_abandoned_prototype_map()),
1311       elements_kind_generalizations_(broker->zone()) {}
1312 
JSFunctionData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSFunction> object)1313 JSFunctionData::JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
1314                                Handle<JSFunction> object)
1315     : JSObjectData(broker, storage, object),
1316       has_feedback_vector_(object->has_feedback_vector()),
1317       has_initial_map_(object->has_prototype_slot() &&
1318                        object->has_initial_map()),
1319       has_prototype_(object->has_prototype_slot() && object->has_prototype()),
1320       has_attached_optimized_code_(object->HasAttachedOptimizedCode()),
1321       PrototypeRequiresRuntimeLookup_(
1322           object->PrototypeRequiresRuntimeLookup()) {}
1323 
Serialize(JSHeapBroker * broker)1324 void JSFunctionData::Serialize(JSHeapBroker* broker) {
1325   if (serialized_) return;
1326   serialized_ = true;
1327 
1328   TraceScope tracer(broker, this, "JSFunctionData::Serialize");
1329   Handle<JSFunction> function = Handle<JSFunction>::cast(object());
1330 
1331   DCHECK_NULL(context_);
1332   DCHECK_NULL(native_context_);
1333   DCHECK_NULL(initial_map_);
1334   DCHECK_NULL(prototype_);
1335   DCHECK_NULL(shared_);
1336   DCHECK_NULL(feedback_cell_);
1337   DCHECK_NULL(feedback_vector_);
1338   DCHECK_NULL(code_);
1339 
1340   context_ = broker->GetOrCreateData(function->context());
1341   native_context_ = broker->GetOrCreateData(function->native_context());
1342   shared_ = broker->GetOrCreateData(function->shared());
1343   feedback_cell_ = broker->GetOrCreateData(function->raw_feedback_cell());
1344   feedback_vector_ = has_feedback_vector()
1345                          ? broker->GetOrCreateData(function->feedback_vector())
1346                          : nullptr;
1347   code_ = broker->GetOrCreateData(function->code());
1348   initial_map_ = has_initial_map()
1349                      ? broker->GetOrCreateData(function->initial_map())
1350                      : nullptr;
1351   prototype_ = has_prototype() ? broker->GetOrCreateData(function->prototype())
1352                                : nullptr;
1353 
1354   if (initial_map_ != nullptr) {
1355     initial_map_instance_size_with_min_slack_ =
1356         function->ComputeInstanceSizeWithMinSlack(broker->isolate());
1357   }
1358   if (initial_map_ != nullptr && !initial_map_->should_access_heap()) {
1359     if (initial_map_->AsMap()->instance_type() == JS_ARRAY_TYPE) {
1360       initial_map_->AsMap()->SerializeElementsKindGeneralizations(broker);
1361     }
1362     initial_map_->AsMap()->SerializeConstructor(broker);
1363     // TODO(neis): This is currently only needed for native_context's
1364     // object_function, as used by GetObjectCreateMap. If no further use sites
1365     // show up, we should move this into NativeContextData::Serialize.
1366     initial_map_->AsMap()->SerializePrototype(broker);
1367   }
1368 }
1369 
SerializeElementsKindGeneralizations(JSHeapBroker * broker)1370 void MapData::SerializeElementsKindGeneralizations(JSHeapBroker* broker) {
1371   if (serialized_elements_kind_generalizations_) return;
1372   serialized_elements_kind_generalizations_ = true;
1373 
1374   TraceScope tracer(broker, this,
1375                     "MapData::SerializeElementsKindGeneralizations");
1376   DCHECK_EQ(instance_type(), JS_ARRAY_TYPE);
1377   MapRef self(broker, this);
1378   ElementsKind from_kind = self.elements_kind();
1379   DCHECK(elements_kind_generalizations_.empty());
1380   for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
1381     ElementsKind to_kind = static_cast<ElementsKind>(i);
1382     if (IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
1383       Handle<Map> target =
1384           Map::AsElementsKind(broker->isolate(), self.object(), to_kind);
1385       elements_kind_generalizations_.push_back(broker->GetOrCreateData(target));
1386     }
1387   }
1388 }
1389 
1390 class DescriptorArrayData : public HeapObjectData {
1391  public:
DescriptorArrayData(JSHeapBroker * broker,ObjectData ** storage,Handle<DescriptorArray> object)1392   DescriptorArrayData(JSHeapBroker* broker, ObjectData** storage,
1393                       Handle<DescriptorArray> object)
1394       : HeapObjectData(broker, storage, object), contents_(broker->zone()) {}
1395 
contents()1396   ZoneMap<int, PropertyDescriptor>& contents() { return contents_; }
1397 
1398  private:
1399   ZoneMap<int, PropertyDescriptor> contents_;
1400 };
1401 
1402 class FeedbackCellData : public HeapObjectData {
1403  public:
1404   FeedbackCellData(JSHeapBroker* broker, ObjectData** storage,
1405                    Handle<FeedbackCell> object);
1406 
value() const1407   ObjectData* value() const { return value_; }
1408 
1409  private:
1410   ObjectData* const value_;
1411 };
1412 
FeedbackCellData(JSHeapBroker * broker,ObjectData ** storage,Handle<FeedbackCell> object)1413 FeedbackCellData::FeedbackCellData(JSHeapBroker* broker, ObjectData** storage,
1414                                    Handle<FeedbackCell> object)
1415     : HeapObjectData(broker, storage, object),
1416       value_(broker->GetOrCreateData(object->value())) {}
1417 
1418 class FeedbackVectorData : public HeapObjectData {
1419  public:
1420   FeedbackVectorData(JSHeapBroker* broker, ObjectData** storage,
1421                      Handle<FeedbackVector> object);
1422 
invocation_count() const1423   double invocation_count() const { return invocation_count_; }
1424 
shared_function_info()1425   ObjectData* shared_function_info() {
1426     CHECK(serialized_);
1427     return shared_function_info_;
1428   }
1429 
1430   void Serialize(JSHeapBroker* broker);
serialized() const1431   bool serialized() const { return serialized_; }
1432   ObjectData* GetClosureFeedbackCell(JSHeapBroker* broker, int index) const;
1433 
1434  private:
1435   double const invocation_count_;
1436 
1437   bool serialized_ = false;
1438   ObjectData* shared_function_info_;
1439   ZoneVector<ObjectData*> closure_feedback_cell_array_;
1440 };
1441 
FeedbackVectorData(JSHeapBroker * broker,ObjectData ** storage,Handle<FeedbackVector> object)1442 FeedbackVectorData::FeedbackVectorData(JSHeapBroker* broker,
1443                                        ObjectData** storage,
1444                                        Handle<FeedbackVector> object)
1445     : HeapObjectData(broker, storage, object),
1446       invocation_count_(object->invocation_count()),
1447       closure_feedback_cell_array_(broker->zone()) {}
1448 
GetClosureFeedbackCell(JSHeapBroker * broker,int index) const1449 ObjectData* FeedbackVectorData::GetClosureFeedbackCell(JSHeapBroker* broker,
1450                                                        int index) const {
1451   CHECK_GE(index, 0);
1452 
1453   size_t cell_array_size = closure_feedback_cell_array_.size();
1454   if (!serialized_) {
1455     DCHECK_EQ(cell_array_size, 0);
1456     TRACE_BROKER_MISSING(broker,
1457                          " closure feedback cell array for vector " << this);
1458     return nullptr;
1459   }
1460   CHECK_LT(index, cell_array_size);
1461   return closure_feedback_cell_array_[index];
1462 }
1463 
Serialize(JSHeapBroker * broker)1464 void FeedbackVectorData::Serialize(JSHeapBroker* broker) {
1465   if (serialized_) return;
1466   serialized_ = true;
1467 
1468   TraceScope tracer(broker, this, "FeedbackVectorData::Serialize");
1469   Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(object());
1470   Handle<SharedFunctionInfo> sfi(vector->shared_function_info(),
1471                                  broker->isolate());
1472   shared_function_info_ = broker->GetOrCreateData(sfi);
1473   DCHECK(closure_feedback_cell_array_.empty());
1474   int length = vector->closure_feedback_cell_array().length();
1475   closure_feedback_cell_array_.reserve(length);
1476   for (int i = 0; i < length; ++i) {
1477     Handle<FeedbackCell> cell = vector->GetClosureFeedbackCell(i);
1478     ObjectData* cell_data = broker->GetOrCreateData(cell);
1479     closure_feedback_cell_array_.push_back(cell_data);
1480   }
1481   TRACE(broker, "Copied " << length << " feedback cells");
1482 }
1483 
1484 class FixedArrayBaseData : public HeapObjectData {
1485  public:
FixedArrayBaseData(JSHeapBroker * broker,ObjectData ** storage,Handle<FixedArrayBase> object)1486   FixedArrayBaseData(JSHeapBroker* broker, ObjectData** storage,
1487                      Handle<FixedArrayBase> object)
1488       : HeapObjectData(broker, storage, object), length_(object->length()) {}
1489 
length() const1490   int length() const { return length_; }
1491 
1492  private:
1493   int const length_;
1494 };
1495 
1496 class FixedArrayData : public FixedArrayBaseData {
1497  public:
1498   FixedArrayData(JSHeapBroker* broker, ObjectData** storage,
1499                  Handle<FixedArray> object);
1500 
1501   // Creates all elements of the fixed array.
1502   void SerializeContents(JSHeapBroker* broker);
1503 
1504   ObjectData* Get(int i) const;
1505 
1506  private:
1507   bool serialized_contents_ = false;
1508   ZoneVector<ObjectData*> contents_;
1509 };
1510 
JSDataViewData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSDataView> object)1511 JSDataViewData::JSDataViewData(JSHeapBroker* broker, ObjectData** storage,
1512                                Handle<JSDataView> object)
1513     : JSObjectData(broker, storage, object),
1514       byte_length_(object->byte_length()) {}
1515 
JSBoundFunctionData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSBoundFunction> object)1516 JSBoundFunctionData::JSBoundFunctionData(JSHeapBroker* broker,
1517                                          ObjectData** storage,
1518                                          Handle<JSBoundFunction> object)
1519     : JSObjectData(broker, storage, object) {}
1520 
Serialize(JSHeapBroker * broker)1521 bool JSBoundFunctionData::Serialize(JSHeapBroker* broker) {
1522   if (serialized_) return true;
1523   if (broker->StackHasOverflowed()) return false;
1524 
1525   TraceScope tracer(broker, this, "JSBoundFunctionData::Serialize");
1526   Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object());
1527 
1528   // We don't immediately set {serialized_} in order to correctly handle the
1529   // case where a recursive call to this method reaches the stack limit.
1530 
1531   DCHECK_NULL(bound_target_function_);
1532   bound_target_function_ =
1533       broker->GetOrCreateData(function->bound_target_function());
1534   bool serialized_nested = true;
1535   if (!bound_target_function_->should_access_heap()) {
1536     if (bound_target_function_->IsJSBoundFunction()) {
1537       serialized_nested =
1538           bound_target_function_->AsJSBoundFunction()->Serialize(broker);
1539     } else if (bound_target_function_->IsJSFunction()) {
1540       bound_target_function_->AsJSFunction()->Serialize(broker);
1541     }
1542   }
1543   if (!serialized_nested) {
1544     // We couldn't serialize all nested bound functions due to stack
1545     // overflow. Give up.
1546     DCHECK(!serialized_);
1547     bound_target_function_ = nullptr;  // Reset to sync with serialized_.
1548     return false;
1549   }
1550 
1551   serialized_ = true;
1552 
1553   DCHECK_NULL(bound_arguments_);
1554   bound_arguments_ = broker->GetOrCreateData(function->bound_arguments());
1555   if (!bound_arguments_->should_access_heap()) {
1556     bound_arguments_->AsFixedArray()->SerializeContents(broker);
1557   }
1558 
1559   DCHECK_NULL(bound_this_);
1560   bound_this_ = broker->GetOrCreateData(function->bound_this());
1561 
1562   return true;
1563 }
1564 
JSObjectData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSObject> object)1565 JSObjectData::JSObjectData(JSHeapBroker* broker, ObjectData** storage,
1566                            Handle<JSObject> object)
1567     : JSReceiverData(broker, storage, object),
1568       inobject_fields_(broker->zone()),
1569       own_constant_elements_(broker->zone()),
1570       own_properties_(broker->zone()) {}
1571 
FixedArrayData(JSHeapBroker * broker,ObjectData ** storage,Handle<FixedArray> object)1572 FixedArrayData::FixedArrayData(JSHeapBroker* broker, ObjectData** storage,
1573                                Handle<FixedArray> object)
1574     : FixedArrayBaseData(broker, storage, object), contents_(broker->zone()) {}
1575 
SerializeContents(JSHeapBroker * broker)1576 void FixedArrayData::SerializeContents(JSHeapBroker* broker) {
1577   if (serialized_contents_) return;
1578   serialized_contents_ = true;
1579 
1580   TraceScope tracer(broker, this, "FixedArrayData::SerializeContents");
1581   Handle<FixedArray> array = Handle<FixedArray>::cast(object());
1582   CHECK_EQ(array->length(), length());
1583   CHECK(contents_.empty());
1584   contents_.reserve(static_cast<size_t>(length()));
1585 
1586   for (int i = 0; i < length(); i++) {
1587     Handle<Object> value(array->get(i), broker->isolate());
1588     contents_.push_back(broker->GetOrCreateData(value));
1589   }
1590   TRACE(broker, "Copied " << contents_.size() << " elements");
1591 }
1592 
1593 class FixedDoubleArrayData : public FixedArrayBaseData {
1594  public:
1595   FixedDoubleArrayData(JSHeapBroker* broker, ObjectData** storage,
1596                        Handle<FixedDoubleArray> object);
1597 
1598   // Serializes all elements of the fixed array.
1599   void SerializeContents(JSHeapBroker* broker);
1600 
1601   Float64 Get(int i) const;
1602 
1603  private:
1604   bool serialized_contents_ = false;
1605   ZoneVector<Float64> contents_;
1606 };
1607 
FixedDoubleArrayData(JSHeapBroker * broker,ObjectData ** storage,Handle<FixedDoubleArray> object)1608 FixedDoubleArrayData::FixedDoubleArrayData(JSHeapBroker* broker,
1609                                            ObjectData** storage,
1610                                            Handle<FixedDoubleArray> object)
1611     : FixedArrayBaseData(broker, storage, object), contents_(broker->zone()) {
1612 }
1613 
SerializeContents(JSHeapBroker * broker)1614 void FixedDoubleArrayData::SerializeContents(JSHeapBroker* broker) {
1615   if (serialized_contents_) return;
1616   serialized_contents_ = true;
1617 
1618   TraceScope tracer(broker, this, "FixedDoubleArrayData::SerializeContents");
1619   Handle<FixedDoubleArray> self = Handle<FixedDoubleArray>::cast(object());
1620   CHECK_EQ(self->length(), length());
1621   CHECK(contents_.empty());
1622   contents_.reserve(static_cast<size_t>(length()));
1623 
1624   for (int i = 0; i < length(); i++) {
1625     contents_.push_back(Float64::FromBits(self->get_representation(i)));
1626   }
1627   TRACE(broker, "Copied " << contents_.size() << " elements");
1628 }
1629 
1630 class BytecodeArrayData : public FixedArrayBaseData {
1631  public:
register_count() const1632   int register_count() const { return register_count_; }
parameter_count() const1633   int parameter_count() const { return parameter_count_; }
incoming_new_target_or_generator_register() const1634   interpreter::Register incoming_new_target_or_generator_register() const {
1635     return incoming_new_target_or_generator_register_;
1636   }
1637 
GetConstantAtIndex(int index,Isolate * isolate) const1638   Handle<Object> GetConstantAtIndex(int index, Isolate* isolate) const {
1639     return constant_pool_[index]->object();
1640   }
1641 
IsConstantAtIndexSmi(int index) const1642   bool IsConstantAtIndexSmi(int index) const {
1643     return constant_pool_[index]->is_smi();
1644   }
1645 
GetConstantAtIndexAsSmi(int index) const1646   Smi GetConstantAtIndexAsSmi(int index) const {
1647     return *(Handle<Smi>::cast(constant_pool_[index]->object()));
1648   }
1649 
SerializeForCompilation(JSHeapBroker * broker)1650   void SerializeForCompilation(JSHeapBroker* broker) {
1651     if (is_serialized_for_compilation_) return;
1652 
1653     // Convinience cast: object() is already a canonical persistent handle.
1654     Handle<BytecodeArray> bytecodes = Handle<BytecodeArray>::cast(object());
1655 
1656     DCHECK(constant_pool_.empty());
1657     Handle<FixedArray> constant_pool(bytecodes->constant_pool(),
1658                                      broker->isolate());
1659     constant_pool_.reserve(constant_pool->length());
1660     for (int i = 0; i < constant_pool->length(); i++) {
1661       constant_pool_.push_back(broker->GetOrCreateData(constant_pool->get(i)));
1662     }
1663 
1664     is_serialized_for_compilation_ = true;
1665   }
1666 
BytecodeArrayData(JSHeapBroker * broker,ObjectData ** storage,Handle<BytecodeArray> object)1667   BytecodeArrayData(JSHeapBroker* broker, ObjectData** storage,
1668                     Handle<BytecodeArray> object)
1669       : FixedArrayBaseData(broker, storage, object),
1670         register_count_(object->register_count()),
1671         parameter_count_(object->parameter_count()),
1672         incoming_new_target_or_generator_register_(
1673             object->incoming_new_target_or_generator_register()),
1674         constant_pool_(broker->zone()) {}
1675 
1676  private:
1677   int const register_count_;
1678   int const parameter_count_;
1679   interpreter::Register const incoming_new_target_or_generator_register_;
1680 
1681   bool is_serialized_for_compilation_ = false;
1682   ZoneVector<ObjectData*> constant_pool_;
1683 };
1684 
1685 class JSArrayData : public JSObjectData {
1686  public:
1687   JSArrayData(JSHeapBroker* broker, ObjectData** storage,
1688               Handle<JSArray> object);
1689 
1690   void Serialize(JSHeapBroker* broker);
length() const1691   ObjectData* length() const { return length_; }
1692 
1693   ObjectData* GetOwnElement(
1694       JSHeapBroker* broker, uint32_t index,
1695       SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
1696 
1697  private:
1698   bool serialized_ = false;
1699   ObjectData* length_ = nullptr;
1700 
1701   // Elements (indexed properties) that either
1702   // (1) are known to exist directly on the object, or
1703   // (2) are known not to (possibly they don't exist at all).
1704   // In case (2), the second pair component is nullptr.
1705   ZoneVector<std::pair<uint32_t, ObjectData*>> own_elements_;
1706 };
1707 
JSArrayData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSArray> object)1708 JSArrayData::JSArrayData(JSHeapBroker* broker, ObjectData** storage,
1709                          Handle<JSArray> object)
1710     : JSObjectData(broker, storage, object), own_elements_(broker->zone()) {}
1711 
Serialize(JSHeapBroker * broker)1712 void JSArrayData::Serialize(JSHeapBroker* broker) {
1713   if (serialized_) return;
1714   serialized_ = true;
1715 
1716   TraceScope tracer(broker, this, "JSArrayData::Serialize");
1717   Handle<JSArray> jsarray = Handle<JSArray>::cast(object());
1718 
1719   DCHECK_NULL(length_);
1720   length_ = broker->GetOrCreateData(jsarray->length());
1721 }
1722 
GetOwnElement(JSHeapBroker * broker,uint32_t index,SerializationPolicy policy)1723 ObjectData* JSArrayData::GetOwnElement(JSHeapBroker* broker, uint32_t index,
1724                                        SerializationPolicy policy) {
1725   for (auto const& p : own_elements_) {
1726     if (p.first == index) return p.second;
1727   }
1728 
1729   if (policy == SerializationPolicy::kAssumeSerialized) {
1730     TRACE_MISSING(broker, "knowledge about index " << index << " on " << this);
1731     return nullptr;
1732   }
1733 
1734   base::Optional<ObjectRef> element =
1735       GetOwnElementFromHeap(broker, object(), index, false);
1736   ObjectData* result = element.has_value() ? element->data() : nullptr;
1737   own_elements_.push_back({index, result});
1738   return result;
1739 }
1740 
1741 class ScopeInfoData : public HeapObjectData {
1742  public:
1743   ScopeInfoData(JSHeapBroker* broker, ObjectData** storage,
1744                 Handle<ScopeInfo> object);
1745 
ContextLength() const1746   int ContextLength() const { return context_length_; }
HasContextExtensionSlot() const1747   bool HasContextExtensionSlot() const { return has_context_extension_slot_; }
HasOuterScopeInfo() const1748   bool HasOuterScopeInfo() const { return has_outer_scope_info_; }
1749 
OuterScopeInfo() const1750   ObjectData* OuterScopeInfo() const { return outer_scope_info_; }
1751   void SerializeScopeInfoChain(JSHeapBroker* broker);
1752 
1753  private:
1754   int const context_length_;
1755   bool const has_context_extension_slot_;
1756   bool const has_outer_scope_info_;
1757 
1758   // Only serialized via SerializeScopeInfoChain.
1759   ObjectData* outer_scope_info_;
1760 };
1761 
ScopeInfoData(JSHeapBroker * broker,ObjectData ** storage,Handle<ScopeInfo> object)1762 ScopeInfoData::ScopeInfoData(JSHeapBroker* broker, ObjectData** storage,
1763                              Handle<ScopeInfo> object)
1764     : HeapObjectData(broker, storage, object),
1765       context_length_(object->ContextLength()),
1766       has_context_extension_slot_(object->HasContextExtensionSlot()),
1767       has_outer_scope_info_(object->HasOuterScopeInfo()),
1768       outer_scope_info_(nullptr) {
1769   DCHECK(!FLAG_turbo_direct_heap_access);
1770 }
1771 
SerializeScopeInfoChain(JSHeapBroker * broker)1772 void ScopeInfoData::SerializeScopeInfoChain(JSHeapBroker* broker) {
1773   if (outer_scope_info_) return;
1774   if (!has_outer_scope_info_) return;
1775   outer_scope_info_ = broker->GetOrCreateData(
1776       Handle<ScopeInfo>::cast(object())->OuterScopeInfo());
1777   if (!outer_scope_info_->should_access_heap()) {
1778     outer_scope_info_->AsScopeInfo()->SerializeScopeInfoChain(broker);
1779   }
1780 }
1781 
1782 class SharedFunctionInfoData : public HeapObjectData {
1783  public:
1784   SharedFunctionInfoData(JSHeapBroker* broker, ObjectData** storage,
1785                          Handle<SharedFunctionInfo> object);
1786 
builtin_id() const1787   int builtin_id() const { return builtin_id_; }
context_header_size() const1788   int context_header_size() const { return context_header_size_; }
GetBytecodeArray() const1789   ObjectData* GetBytecodeArray() const { return GetBytecodeArray_; }
GetInlineability() const1790   SharedFunctionInfo::Inlineability GetInlineability() const {
1791     return inlineability_;
1792   }
1793   void SerializeFunctionTemplateInfo(JSHeapBroker* broker);
scope_info() const1794   ObjectData* scope_info() const { return scope_info_; }
1795   void SerializeScopeInfoChain(JSHeapBroker* broker);
function_template_info() const1796   ObjectData* function_template_info() const { return function_template_info_; }
GetTemplateObject(FeedbackSlot slot) const1797   ObjectData* GetTemplateObject(FeedbackSlot slot) const {
1798     auto lookup_it = template_objects_.find(slot.ToInt());
1799     if (lookup_it != template_objects_.cend()) {
1800       return lookup_it->second;
1801     }
1802     return nullptr;
1803   }
SetTemplateObject(FeedbackSlot slot,ObjectData * object)1804   void SetTemplateObject(FeedbackSlot slot, ObjectData* object) {
1805     CHECK(
1806         template_objects_.insert(std::make_pair(slot.ToInt(), object)).second);
1807   }
1808 
1809 #define DECL_ACCESSOR(type, name) \
1810   type name() const { return name##_; }
1811   BROKER_SFI_FIELDS(DECL_ACCESSOR)
1812 #undef DECL_ACCESSOR
1813 
1814  private:
1815   int const builtin_id_;
1816   int const context_header_size_;
1817   ObjectData* const GetBytecodeArray_;
1818 #define DECL_MEMBER(type, name) type const name##_;
1819   BROKER_SFI_FIELDS(DECL_MEMBER)
1820 #undef DECL_MEMBER
1821   SharedFunctionInfo::Inlineability const inlineability_;
1822   ObjectData* function_template_info_;
1823   ZoneMap<int, ObjectData*> template_objects_;
1824   ObjectData* scope_info_;
1825 };
1826 
SharedFunctionInfoData(JSHeapBroker * broker,ObjectData ** storage,Handle<SharedFunctionInfo> object)1827 SharedFunctionInfoData::SharedFunctionInfoData(
1828     JSHeapBroker* broker, ObjectData** storage,
1829     Handle<SharedFunctionInfo> object)
1830     : HeapObjectData(broker, storage, object),
1831       builtin_id_(object->HasBuiltinId() ? object->builtin_id()
1832                                          : Builtins::kNoBuiltinId),
1833       context_header_size_(object->scope_info().ContextHeaderLength()),
1834       GetBytecodeArray_(
1835           object->HasBytecodeArray()
1836               ? broker->GetOrCreateData(object->GetBytecodeArray())
1837               : nullptr)
1838 #define INIT_MEMBER(type, name) , name##_(object->name())
1839           BROKER_SFI_FIELDS(INIT_MEMBER)
1840 #undef INIT_MEMBER
1841       ,
1842       inlineability_(object->GetInlineability()),
1843       function_template_info_(nullptr),
1844       template_objects_(broker->zone()),
1845       scope_info_(nullptr) {
1846   DCHECK_EQ(HasBuiltinId_, builtin_id_ != Builtins::kNoBuiltinId);
1847   DCHECK_EQ(HasBytecodeArray_, GetBytecodeArray_ != nullptr);
1848 }
1849 
SerializeFunctionTemplateInfo(JSHeapBroker * broker)1850 void SharedFunctionInfoData::SerializeFunctionTemplateInfo(
1851     JSHeapBroker* broker) {
1852   if (function_template_info_) return;
1853   function_template_info_ = broker->GetOrCreateData(
1854       Handle<SharedFunctionInfo>::cast(object())->function_data(kAcquireLoad));
1855 }
1856 
SerializeScopeInfoChain(JSHeapBroker * broker)1857 void SharedFunctionInfoData::SerializeScopeInfoChain(JSHeapBroker* broker) {
1858   if (scope_info_) return;
1859   scope_info_ = broker->GetOrCreateData(
1860       Handle<SharedFunctionInfo>::cast(object())->scope_info());
1861   if (!scope_info_->should_access_heap()) {
1862     scope_info_->AsScopeInfo()->SerializeScopeInfoChain(broker);
1863   }
1864 }
1865 
1866 class SourceTextModuleData : public HeapObjectData {
1867  public:
1868   SourceTextModuleData(JSHeapBroker* broker, ObjectData** storage,
1869                        Handle<SourceTextModule> object);
1870   void Serialize(JSHeapBroker* broker);
1871 
1872   ObjectData* GetCell(JSHeapBroker* broker, int cell_index) const;
1873   ObjectData* GetImportMeta(JSHeapBroker* broker) const;
1874 
1875  private:
1876   bool serialized_ = false;
1877   ZoneVector<ObjectData*> imports_;
1878   ZoneVector<ObjectData*> exports_;
1879   ObjectData* import_meta_;
1880 };
1881 
SourceTextModuleData(JSHeapBroker * broker,ObjectData ** storage,Handle<SourceTextModule> object)1882 SourceTextModuleData::SourceTextModuleData(JSHeapBroker* broker,
1883                                            ObjectData** storage,
1884                                            Handle<SourceTextModule> object)
1885     : HeapObjectData(broker, storage, object),
1886       imports_(broker->zone()),
1887       exports_(broker->zone()),
1888       import_meta_(nullptr) {}
1889 
GetCell(JSHeapBroker * broker,int cell_index) const1890 ObjectData* SourceTextModuleData::GetCell(JSHeapBroker* broker,
1891                                           int cell_index) const {
1892   if (!serialized_) {
1893     DCHECK(imports_.empty());
1894     TRACE_BROKER_MISSING(broker,
1895                          "module cell " << cell_index << " on " << this);
1896     return nullptr;
1897   }
1898   ObjectData* cell;
1899   switch (SourceTextModuleDescriptor::GetCellIndexKind(cell_index)) {
1900     case SourceTextModuleDescriptor::kImport:
1901       cell = imports_.at(SourceTextModule::ImportIndex(cell_index));
1902       break;
1903     case SourceTextModuleDescriptor::kExport:
1904       cell = exports_.at(SourceTextModule::ExportIndex(cell_index));
1905       break;
1906     case SourceTextModuleDescriptor::kInvalid:
1907       UNREACHABLE();
1908   }
1909   CHECK_NOT_NULL(cell);
1910   return cell;
1911 }
1912 
GetImportMeta(JSHeapBroker * broker) const1913 ObjectData* SourceTextModuleData::GetImportMeta(JSHeapBroker* broker) const {
1914   CHECK(serialized_);
1915   return import_meta_;
1916 }
1917 
Serialize(JSHeapBroker * broker)1918 void SourceTextModuleData::Serialize(JSHeapBroker* broker) {
1919   if (serialized_) return;
1920   serialized_ = true;
1921 
1922   TraceScope tracer(broker, this, "SourceTextModuleData::Serialize");
1923   Handle<SourceTextModule> module = Handle<SourceTextModule>::cast(object());
1924 
1925   // TODO(neis): We could be smarter and only serialize the cells we care about.
1926   // TODO(neis): Define a helper for serializing a FixedArray into a ZoneVector.
1927 
1928   DCHECK(imports_.empty());
1929   Handle<FixedArray> imports(module->regular_imports(), broker->isolate());
1930   int const imports_length = imports->length();
1931   imports_.reserve(imports_length);
1932   for (int i = 0; i < imports_length; ++i) {
1933     imports_.push_back(broker->GetOrCreateData(imports->get(i)));
1934   }
1935   TRACE(broker, "Copied " << imports_.size() << " imports");
1936 
1937   DCHECK(exports_.empty());
1938   Handle<FixedArray> exports(module->regular_exports(), broker->isolate());
1939   int const exports_length = exports->length();
1940   exports_.reserve(exports_length);
1941   for (int i = 0; i < exports_length; ++i) {
1942     exports_.push_back(broker->GetOrCreateData(exports->get(i)));
1943   }
1944   TRACE(broker, "Copied " << exports_.size() << " exports");
1945 
1946   DCHECK_NULL(import_meta_);
1947   import_meta_ = broker->GetOrCreateData(module->import_meta());
1948   TRACE(broker, "Copied import_meta");
1949 }
1950 
1951 class CellData : public HeapObjectData {
1952  public:
CellData(JSHeapBroker * broker,ObjectData ** storage,Handle<Cell> object)1953   CellData(JSHeapBroker* broker, ObjectData** storage, Handle<Cell> object)
1954       : HeapObjectData(broker, storage, object) {
1955     DCHECK(!FLAG_turbo_direct_heap_access);
1956   }
1957 };
1958 
1959 class JSGlobalObjectData : public JSObjectData {
1960  public:
1961   JSGlobalObjectData(JSHeapBroker* broker, ObjectData** storage,
1962                      Handle<JSGlobalObject> object);
IsDetached() const1963   bool IsDetached() const { return is_detached_; }
1964 
1965   ObjectData* GetPropertyCell(
1966       JSHeapBroker* broker, ObjectData* name,
1967       SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
1968 
1969  private:
1970   bool const is_detached_;
1971 
1972   // Properties that either
1973   // (1) are known to exist as property cells on the global object, or
1974   // (2) are known not to (possibly they don't exist at all).
1975   // In case (2), the second pair component is nullptr.
1976   ZoneVector<std::pair<ObjectData*, ObjectData*>> properties_;
1977 };
1978 
JSGlobalObjectData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSGlobalObject> object)1979 JSGlobalObjectData::JSGlobalObjectData(JSHeapBroker* broker,
1980                                        ObjectData** storage,
1981                                        Handle<JSGlobalObject> object)
1982     : JSObjectData(broker, storage, object),
1983       is_detached_(object->IsDetached()),
1984       properties_(broker->zone()) {}
1985 
1986 class JSGlobalProxyData : public JSObjectData {
1987  public:
1988   JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage,
1989                     Handle<JSGlobalProxy> object);
1990 };
1991 
JSGlobalProxyData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSGlobalProxy> object)1992 JSGlobalProxyData::JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage,
1993                                      Handle<JSGlobalProxy> object)
1994     : JSObjectData(broker, storage, object) {}
1995 
1996 namespace {
GetPropertyCellFromHeap(JSHeapBroker * broker,Handle<Name> name)1997 base::Optional<PropertyCellRef> GetPropertyCellFromHeap(JSHeapBroker* broker,
1998                                                         Handle<Name> name) {
1999   LookupIterator it(
2000       broker->isolate(),
2001       handle(broker->target_native_context().object()->global_object(),
2002              broker->isolate()),
2003       name, LookupIterator::OWN);
2004   it.TryLookupCachedProperty();
2005   if (it.state() == LookupIterator::DATA &&
2006       it.GetHolder<JSObject>()->IsJSGlobalObject()) {
2007     return PropertyCellRef(broker, it.GetPropertyCell());
2008   }
2009   return base::nullopt;
2010 }
2011 }  // namespace
2012 
GetPropertyCell(JSHeapBroker * broker,ObjectData * name,SerializationPolicy policy)2013 ObjectData* JSGlobalObjectData::GetPropertyCell(JSHeapBroker* broker,
2014                                                 ObjectData* name,
2015                                                 SerializationPolicy policy) {
2016   CHECK_NOT_NULL(name);
2017   for (auto const& p : properties_) {
2018     if (p.first == name) return p.second;
2019   }
2020 
2021   if (policy == SerializationPolicy::kAssumeSerialized) {
2022     TRACE_MISSING(broker, "knowledge about global property " << name);
2023     return nullptr;
2024   }
2025 
2026   ObjectData* result = nullptr;
2027   base::Optional<PropertyCellRef> cell =
2028       GetPropertyCellFromHeap(broker, Handle<Name>::cast(name->object()));
2029   if (cell.has_value()) {
2030     result = cell->data();
2031     if (!result->should_access_heap()) {
2032       result->AsPropertyCell()->Serialize(broker);
2033     }
2034   }
2035   properties_.push_back({name, result});
2036   return result;
2037 }
2038 
2039 class TemplateObjectDescriptionData : public HeapObjectData {
2040  public:
TemplateObjectDescriptionData(JSHeapBroker * broker,ObjectData ** storage,Handle<TemplateObjectDescription> object)2041   TemplateObjectDescriptionData(JSHeapBroker* broker, ObjectData** storage,
2042                                 Handle<TemplateObjectDescription> object)
2043       : HeapObjectData(broker, storage, object) {
2044     DCHECK(!FLAG_turbo_direct_heap_access);
2045   }
2046 };
2047 
2048 class CodeData : public HeapObjectData {
2049  public:
CodeData(JSHeapBroker * broker,ObjectData ** storage,Handle<Code> object)2050   CodeData(JSHeapBroker* broker, ObjectData** storage, Handle<Code> object)
2051       : HeapObjectData(broker, storage, object),
2052         inlined_bytecode_size_(object->inlined_bytecode_size()) {}
2053 
inlined_bytecode_size() const2054   unsigned inlined_bytecode_size() const { return inlined_bytecode_size_; }
2055 
2056  private:
2057   unsigned const inlined_bytecode_size_;
2058 };
2059 
2060 #define DEFINE_IS(Name)                                                 \
2061   bool ObjectData::Is##Name() const {                                   \
2062     if (should_access_heap()) {                                         \
2063       AllowHandleDereferenceIfNeeded allow_handle_dereference(kind());  \
2064       return object()->Is##Name();                                      \
2065     }                                                                   \
2066     if (is_smi()) return false;                                         \
2067     InstanceType instance_type =                                        \
2068         static_cast<const HeapObjectData*>(this)->GetMapInstanceType(); \
2069     return InstanceTypeChecker::Is##Name(instance_type);                \
2070   }
2071 HEAP_BROKER_SERIALIZED_OBJECT_LIST(DEFINE_IS)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DEFINE_IS)2072 HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DEFINE_IS)
2073 #undef DEFINE_IS
2074 
2075 #define DEFINE_AS(Name)                     \
2076   Name##Data* ObjectData::As##Name() {      \
2077     CHECK(Is##Name());                      \
2078     CHECK_EQ(kind_, kSerializedHeapObject); \
2079     return static_cast<Name##Data*>(this);  \
2080   }
2081 HEAP_BROKER_SERIALIZED_OBJECT_LIST(DEFINE_AS)
2082 #undef DEFINE_AS
2083 
2084 // TODO(solanes, v8:10866): Remove once FLAG_turbo_direct_heap_access is
2085 // removed.
2086 // This macro defines the Asxxx methods for NeverSerialized objects, which
2087 // should only be used with direct heap access off.
2088 #define DEFINE_AS(Name)                     \
2089   Name##Data* ObjectData::As##Name() {      \
2090     DCHECK(!FLAG_turbo_direct_heap_access); \
2091     CHECK(Is##Name());                      \
2092     CHECK_EQ(kind_, kSerializedHeapObject); \
2093     return static_cast<Name##Data*>(this);  \
2094   }
2095 HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DEFINE_AS)
2096 #undef DEFINE_AS
2097 
2098 const JSObjectField& JSObjectData::GetInobjectField(int property_index) const {
2099   CHECK_LT(static_cast<size_t>(property_index), inobject_fields_.size());
2100   return inobject_fields_[property_index];
2101 }
2102 
cow_or_empty_elements_tenured() const2103 bool JSObjectData::cow_or_empty_elements_tenured() const {
2104   return cow_or_empty_elements_tenured_;
2105 }
2106 
elements() const2107 ObjectData* JSObjectData::elements() const { return elements_; }
2108 
SerializeAsBoilerplate(JSHeapBroker * broker)2109 void JSObjectData::SerializeAsBoilerplate(JSHeapBroker* broker) {
2110   SerializeRecursiveAsBoilerplate(broker, kMaxFastLiteralDepth);
2111 }
2112 
SerializeElements(JSHeapBroker * broker)2113 void JSObjectData::SerializeElements(JSHeapBroker* broker) {
2114   if (serialized_elements_) return;
2115   serialized_elements_ = true;
2116 
2117   TraceScope tracer(broker, this, "JSObjectData::SerializeElements");
2118   Handle<JSObject> boilerplate = Handle<JSObject>::cast(object());
2119   Handle<FixedArrayBase> elements_object(boilerplate->elements(),
2120                                          broker->isolate());
2121   DCHECK_NULL(elements_);
2122   elements_ = broker->GetOrCreateData(elements_object);
2123   DCHECK(elements_->IsFixedArrayBase());
2124 }
2125 
SerializeConstructor(JSHeapBroker * broker)2126 void MapData::SerializeConstructor(JSHeapBroker* broker) {
2127   if (serialized_constructor_) return;
2128   serialized_constructor_ = true;
2129 
2130   TraceScope tracer(broker, this, "MapData::SerializeConstructor");
2131   Handle<Map> map = Handle<Map>::cast(object());
2132   DCHECK(!map->IsContextMap());
2133   DCHECK_NULL(constructor_);
2134   constructor_ = broker->GetOrCreateData(map->GetConstructor());
2135 }
2136 
SerializeBackPointer(JSHeapBroker * broker)2137 void MapData::SerializeBackPointer(JSHeapBroker* broker) {
2138   if (serialized_backpointer_) return;
2139   serialized_backpointer_ = true;
2140 
2141   TraceScope tracer(broker, this, "MapData::SerializeBackPointer");
2142   Handle<Map> map = Handle<Map>::cast(object());
2143   DCHECK_NULL(backpointer_);
2144   DCHECK(!map->IsContextMap());
2145   backpointer_ = broker->GetOrCreateData(map->GetBackPointer());
2146 }
2147 
SerializePrototype(JSHeapBroker * broker)2148 void MapData::SerializePrototype(JSHeapBroker* broker) {
2149   if (serialized_prototype_) return;
2150   serialized_prototype_ = true;
2151 
2152   TraceScope tracer(broker, this, "MapData::SerializePrototype");
2153   Handle<Map> map = Handle<Map>::cast(object());
2154   DCHECK_NULL(prototype_);
2155   prototype_ = broker->GetOrCreateData(map->prototype());
2156 }
2157 
SerializeOwnDescriptors(JSHeapBroker * broker)2158 void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) {
2159   if (serialized_own_descriptors_) return;
2160   serialized_own_descriptors_ = true;
2161 
2162   TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptors");
2163   Handle<Map> map = Handle<Map>::cast(object());
2164 
2165   for (InternalIndex i : map->IterateOwnDescriptors()) {
2166     SerializeOwnDescriptor(broker, i);
2167   }
2168 }
2169 
GetStrongValue(InternalIndex descriptor_index) const2170 ObjectData* MapData::GetStrongValue(InternalIndex descriptor_index) const {
2171   auto data = instance_descriptors_->contents().find(descriptor_index.as_int());
2172   if (data == instance_descriptors_->contents().end()) return nullptr;
2173   return data->second.value;
2174 }
2175 
SerializeOwnDescriptor(JSHeapBroker * broker,InternalIndex descriptor_index)2176 void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
2177                                      InternalIndex descriptor_index) {
2178   TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptor");
2179   Handle<Map> map = Handle<Map>::cast(object());
2180 
2181   if (instance_descriptors_ == nullptr) {
2182     instance_descriptors_ =
2183         broker->GetOrCreateData(map->instance_descriptors(kRelaxedLoad))
2184             ->AsDescriptorArray();
2185   }
2186 
2187   ZoneMap<int, PropertyDescriptor>& contents =
2188       instance_descriptors()->contents();
2189   CHECK_LT(descriptor_index.as_int(), map->NumberOfOwnDescriptors());
2190   if (contents.find(descriptor_index.as_int()) != contents.end()) return;
2191 
2192   Isolate* const isolate = broker->isolate();
2193   auto descriptors =
2194       Handle<DescriptorArray>::cast(instance_descriptors_->object());
2195   CHECK_EQ(*descriptors, map->instance_descriptors(kRelaxedLoad));
2196 
2197   PropertyDescriptor d;
2198   d.key = broker->GetOrCreateData(descriptors->GetKey(descriptor_index));
2199   MaybeObject value = descriptors->GetValue(descriptor_index);
2200   HeapObject obj;
2201   if (value.GetHeapObjectIfStrong(&obj)) {
2202     d.value = broker->GetOrCreateData(obj);
2203   }
2204   d.details = descriptors->GetDetails(descriptor_index);
2205   if (d.details.location() == kField) {
2206     d.field_index = FieldIndex::ForDescriptor(*map, descriptor_index);
2207     d.field_owner =
2208         broker->GetOrCreateData(map->FindFieldOwner(isolate, descriptor_index));
2209     d.field_type =
2210         broker->GetOrCreateData(descriptors->GetFieldType(descriptor_index));
2211     d.is_unboxed_double_field = map->IsUnboxedDoubleField(d.field_index);
2212   }
2213   contents[descriptor_index.as_int()] = d;
2214 
2215   if (d.details.location() == kField && !d.field_owner->should_access_heap()) {
2216     // Recurse on the owner map.
2217     d.field_owner->AsMap()->SerializeOwnDescriptor(broker, descriptor_index);
2218   }
2219 
2220   TRACE(broker, "Copied descriptor " << descriptor_index.as_int() << " into "
2221                                      << instance_descriptors_ << " ("
2222                                      << contents.size() << " total)");
2223 }
2224 
SerializeRootMap(JSHeapBroker * broker)2225 void MapData::SerializeRootMap(JSHeapBroker* broker) {
2226   if (serialized_root_map_) return;
2227   serialized_root_map_ = true;
2228 
2229   TraceScope tracer(broker, this, "MapData::SerializeRootMap");
2230   Handle<Map> map = Handle<Map>::cast(object());
2231   DCHECK_NULL(root_map_);
2232   root_map_ = broker->GetOrCreateData(map->FindRootMap(broker->isolate()));
2233 }
2234 
FindRootMap() const2235 ObjectData* MapData::FindRootMap() const { return root_map_; }
2236 
SerializeRecursiveAsBoilerplate(JSHeapBroker * broker,int depth)2237 void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker,
2238                                                    int depth) {
2239   if (serialized_as_boilerplate_) return;
2240   serialized_as_boilerplate_ = true;
2241 
2242   TraceScope tracer(broker, this,
2243                     "JSObjectData::SerializeRecursiveAsBoilerplate");
2244   Handle<JSObject> boilerplate = Handle<JSObject>::cast(object());
2245 
2246   // We only serialize boilerplates that pass the IsInlinableFastLiteral
2247   // check, so we only do a check on the depth here.
2248   CHECK_GT(depth, 0);
2249   CHECK(!boilerplate->map().is_deprecated());
2250 
2251   // Serialize the elements.
2252   Isolate* const isolate = broker->isolate();
2253   Handle<FixedArrayBase> elements_object(boilerplate->elements(), isolate);
2254 
2255   // Boilerplates need special serialization - we need to make sure COW arrays
2256   // are tenured. Boilerplate objects should only be reachable from their
2257   // allocation site, so it is safe to assume that the elements have not been
2258   // serialized yet.
2259 
2260   bool const empty_or_cow =
2261       elements_object->length() == 0 ||
2262       elements_object->map() == ReadOnlyRoots(isolate).fixed_cow_array_map();
2263   if (empty_or_cow) {
2264     // We need to make sure copy-on-write elements are tenured.
2265     if (ObjectInYoungGeneration(*elements_object)) {
2266       elements_object = isolate->factory()->CopyAndTenureFixedCOWArray(
2267           Handle<FixedArray>::cast(elements_object));
2268       boilerplate->set_elements(*elements_object);
2269     }
2270     cow_or_empty_elements_tenured_ = true;
2271   }
2272 
2273   DCHECK_NULL(elements_);
2274   elements_ = broker->GetOrCreateData(elements_object);
2275   DCHECK(elements_->IsFixedArrayBase());
2276 
2277   if (empty_or_cow || elements_->should_access_heap()) {
2278     // No need to do anything here. Empty or copy-on-write elements
2279     // do not need to be serialized because we only need to store the elements
2280     // reference to the allocated object.
2281   } else if (boilerplate->HasSmiOrObjectElements()) {
2282     elements_->AsFixedArray()->SerializeContents(broker);
2283     Handle<FixedArray> fast_elements =
2284         Handle<FixedArray>::cast(elements_object);
2285     int length = elements_object->length();
2286     for (int i = 0; i < length; i++) {
2287       Handle<Object> value(fast_elements->get(i), isolate);
2288       if (value->IsJSObject()) {
2289         ObjectData* value_data = broker->GetOrCreateData(value);
2290         if (!value_data->should_access_heap()) {
2291           value_data->AsJSObject()->SerializeRecursiveAsBoilerplate(broker,
2292                                                                     depth - 1);
2293         }
2294       }
2295     }
2296   } else {
2297     CHECK(boilerplate->HasDoubleElements());
2298     CHECK_LE(elements_object->Size(), kMaxRegularHeapObjectSize);
2299     DCHECK_EQ(elements_->kind(), ObjectDataKind::kSerializedHeapObject);
2300     elements_->AsFixedDoubleArray()->SerializeContents(broker);
2301   }
2302 
2303   // TODO(turbofan): Do we want to support out-of-object properties?
2304   CHECK(boilerplate->HasFastProperties() &&
2305         boilerplate->property_array().length() == 0);
2306   CHECK_EQ(inobject_fields_.size(), 0u);
2307 
2308   // Check the in-object properties.
2309   Handle<DescriptorArray> descriptors(
2310       boilerplate->map().instance_descriptors(kRelaxedLoad), isolate);
2311   for (InternalIndex i : boilerplate->map().IterateOwnDescriptors()) {
2312     PropertyDetails details = descriptors->GetDetails(i);
2313     if (details.location() != kField) continue;
2314     DCHECK_EQ(kData, details.kind());
2315 
2316     FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
2317     // Make sure {field_index} agrees with {inobject_properties} on the index of
2318     // this field.
2319     DCHECK_EQ(field_index.property_index(),
2320               static_cast<int>(inobject_fields_.size()));
2321     if (boilerplate->IsUnboxedDoubleField(field_index)) {
2322       uint64_t value_bits =
2323           boilerplate->RawFastDoublePropertyAsBitsAt(field_index);
2324       inobject_fields_.push_back(JSObjectField{value_bits});
2325     } else {
2326       Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
2327                            isolate);
2328       // In case of double fields we use a sentinel NaN value to mark
2329       // uninitialized fields. A boilerplate value with such a field may migrate
2330       // from its double to a tagged representation. If the double is unboxed,
2331       // the raw double is converted to a heap number, otherwise the (boxed)
2332       // double ceases to be mutable, and becomes a normal heap number. The
2333       // sentinel value carries no special meaning when it occurs in a heap
2334       // number, so we would like to recover the uninitialized value. We check
2335       // for the sentinel here, specifically, since migrations might have been
2336       // triggered as part of boilerplate serialization.
2337       if (!details.representation().IsDouble() && value->IsHeapNumber() &&
2338           HeapNumber::cast(*value).value_as_bits() == kHoleNanInt64) {
2339         value = isolate->factory()->uninitialized_value();
2340       }
2341       ObjectData* value_data = broker->GetOrCreateData(value);
2342       if (value_data->IsJSObject() && !value_data->should_access_heap()) {
2343         value_data->AsJSObject()->SerializeRecursiveAsBoilerplate(broker,
2344                                                                   depth - 1);
2345       }
2346       inobject_fields_.push_back(JSObjectField{value_data});
2347     }
2348   }
2349   TRACE(broker, "Copied " << inobject_fields_.size() << " in-object fields");
2350 
2351   if (!map()->should_access_heap()) {
2352     map()->AsMap()->SerializeOwnDescriptors(broker);
2353   }
2354 
2355   if (IsJSArray()) AsJSArray()->Serialize(broker);
2356 }
2357 
SerializeAsRegExpBoilerplate(JSHeapBroker * broker)2358 void JSRegExpData::SerializeAsRegExpBoilerplate(JSHeapBroker* broker) {
2359   if (serialized_as_reg_exp_boilerplate_) return;
2360   serialized_as_reg_exp_boilerplate_ = true;
2361 
2362   TraceScope tracer(broker, this, "JSRegExpData::SerializeAsRegExpBoilerplate");
2363   Handle<JSRegExp> boilerplate = Handle<JSRegExp>::cast(object());
2364 
2365   SerializeElements(broker);
2366 
2367   raw_properties_or_hash_ =
2368       broker->GetOrCreateData(boilerplate->raw_properties_or_hash());
2369   data_ = broker->GetOrCreateData(boilerplate->data());
2370   source_ = broker->GetOrCreateData(boilerplate->source());
2371   flags_ = broker->GetOrCreateData(boilerplate->flags());
2372   last_index_ = broker->GetOrCreateData(boilerplate->last_index());
2373 }
2374 
equals(const ObjectRef & other) const2375 bool ObjectRef::equals(const ObjectRef& other) const {
2376 #ifdef DEBUG
2377   if (broker()->mode() == JSHeapBroker::kSerialized &&
2378       data_->used_status == ObjectData::Usage::kUnused) {
2379     data_->used_status = ObjectData::Usage::kOnlyIdentityUsed;
2380   }
2381 #endif  // DEBUG
2382   return data_ == other.data_;
2383 }
2384 
isolate() const2385 Isolate* ObjectRef::isolate() const { return broker()->isolate(); }
2386 
previous(size_t * depth,SerializationPolicy policy) const2387 ContextRef ContextRef::previous(size_t* depth,
2388                                 SerializationPolicy policy) const {
2389   DCHECK_NOT_NULL(depth);
2390 
2391   if (data_->should_access_heap()) {
2392     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
2393                                                           broker()->mode());
2394     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
2395                                                             broker()->mode());
2396     Context current = *object();
2397     while (*depth != 0 && current.unchecked_previous().IsContext()) {
2398       current = Context::cast(current.unchecked_previous());
2399       (*depth)--;
2400     }
2401     return ContextRef(broker(), broker()->CanonicalPersistentHandle(current));
2402   }
2403 
2404   if (*depth == 0) return *this;
2405 
2406   ObjectData* previous_data = data()->AsContext()->previous(broker(), policy);
2407   if (previous_data == nullptr || !previous_data->IsContext()) return *this;
2408 
2409   *depth = *depth - 1;
2410   return ContextRef(broker(), previous_data).previous(depth, policy);
2411 }
2412 
get(int index,SerializationPolicy policy) const2413 base::Optional<ObjectRef> ContextRef::get(int index,
2414                                           SerializationPolicy policy) const {
2415   if (data_->should_access_heap()) {
2416     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
2417                                                           broker()->mode());
2418     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
2419                                                             broker()->mode());
2420     Handle<Object> value(object()->get(index), broker()->isolate());
2421     return ObjectRef(broker(), value);
2422   }
2423   ObjectData* optional_slot =
2424       data()->AsContext()->GetSlot(broker(), index, policy);
2425   if (optional_slot != nullptr) {
2426     return ObjectRef(broker(), optional_slot);
2427   }
2428   return base::nullopt;
2429 }
2430 
GetModule(SerializationPolicy policy) const2431 SourceTextModuleRef ContextRef::GetModule(SerializationPolicy policy) const {
2432   ContextRef current = *this;
2433   while (current.map().instance_type() != MODULE_CONTEXT_TYPE) {
2434     size_t depth = 1;
2435     current = current.previous(&depth, policy);
2436     CHECK_EQ(depth, 0);
2437   }
2438   return current.get(Context::EXTENSION_INDEX, policy)
2439       .value()
2440       .AsSourceTextModule();
2441 }
2442 
JSHeapBroker(Isolate * isolate,Zone * broker_zone,bool tracing_enabled,bool is_concurrent_inlining,CodeKind code_kind)2443 JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone,
2444                            bool tracing_enabled, bool is_concurrent_inlining,
2445                            CodeKind code_kind)
2446     : isolate_(isolate),
2447       zone_(broker_zone),
2448       refs_(zone()->New<RefsMap>(kMinimalRefsBucketCount, AddressMatcher(),
2449                                  zone())),
2450       root_index_map_(isolate),
2451       array_and_object_prototypes_(zone()),
2452       tracing_enabled_(tracing_enabled),
2453       is_concurrent_inlining_(is_concurrent_inlining),
2454       code_kind_(code_kind),
2455       feedback_(zone()),
2456       bytecode_analyses_(zone()),
2457       property_access_infos_(zone()),
2458       minimorphic_property_access_infos_(zone()),
2459       typed_array_string_tags_(zone()),
2460       serialized_functions_(zone()) {
2461   // Note that this initialization of {refs_} with the minimal initial capacity
2462   // is redundant in the normal use case (concurrent compilation enabled,
2463   // standard objects to be serialized), as the map is going to be replaced
2464   // immediately with a larger-capacity one.  It doesn't seem to affect the
2465   // performance in a noticeable way though.
2466   TRACE(this, "Constructing heap broker");
2467 }
2468 
~JSHeapBroker()2469 JSHeapBroker::~JSHeapBroker() { DCHECK_NULL(local_isolate_); }
2470 
SetPersistentAndCopyCanonicalHandlesForTesting(std::unique_ptr<PersistentHandles> persistent_handles,std::unique_ptr<CanonicalHandlesMap> canonical_handles)2471 void JSHeapBroker::SetPersistentAndCopyCanonicalHandlesForTesting(
2472     std::unique_ptr<PersistentHandles> persistent_handles,
2473     std::unique_ptr<CanonicalHandlesMap> canonical_handles) {
2474   set_persistent_handles(std::move(persistent_handles));
2475   CopyCanonicalHandlesForTesting(std::move(canonical_handles));
2476 }
2477 
CopyCanonicalHandlesForTesting(std::unique_ptr<CanonicalHandlesMap> canonical_handles)2478 void JSHeapBroker::CopyCanonicalHandlesForTesting(
2479     std::unique_ptr<CanonicalHandlesMap> canonical_handles) {
2480   DCHECK_NULL(canonical_handles_);
2481   canonical_handles_ = std::make_unique<CanonicalHandlesMap>(
2482       isolate_->heap(), ZoneAllocationPolicy(zone()));
2483 
2484   CanonicalHandlesMap::IteratableScope it_scope(canonical_handles.get());
2485   for (auto it = it_scope.begin(); it != it_scope.end(); ++it) {
2486     Address* entry = *it.entry();
2487     Object key = it.key();
2488     canonical_handles_->Insert(key, entry);
2489   }
2490 }
2491 
Trace() const2492 std::string JSHeapBroker::Trace() const {
2493   std::ostringstream oss;
2494   oss << "[" << this << "] ";
2495   for (unsigned i = 0; i < trace_indentation_ * 2; ++i) oss.put(' ');
2496   return oss.str();
2497 }
2498 
AttachLocalIsolate(OptimizedCompilationInfo * info,LocalIsolate * local_isolate)2499 void JSHeapBroker::AttachLocalIsolate(OptimizedCompilationInfo* info,
2500                                       LocalIsolate* local_isolate) {
2501   set_canonical_handles(info->DetachCanonicalHandles());
2502   DCHECK_NULL(local_isolate_);
2503   local_isolate_ = local_isolate;
2504   DCHECK_NOT_NULL(local_isolate_);
2505   local_isolate_->heap()->AttachPersistentHandles(
2506       info->DetachPersistentHandles());
2507 }
2508 
DetachLocalIsolate(OptimizedCompilationInfo * info)2509 void JSHeapBroker::DetachLocalIsolate(OptimizedCompilationInfo* info) {
2510   DCHECK_NULL(ph_);
2511   DCHECK_NOT_NULL(local_isolate_);
2512   std::unique_ptr<PersistentHandles> ph =
2513       local_isolate_->heap()->DetachPersistentHandles();
2514   local_isolate_ = nullptr;
2515   info->set_canonical_handles(DetachCanonicalHandles());
2516   info->set_persistent_handles(std::move(ph));
2517 }
2518 
StopSerializing()2519 void JSHeapBroker::StopSerializing() {
2520   CHECK_EQ(mode_, kSerializing);
2521   TRACE(this, "Stopping serialization");
2522   mode_ = kSerialized;
2523 }
2524 
2525 #ifdef DEBUG
PrintRefsAnalysis() const2526 void JSHeapBroker::PrintRefsAnalysis() const {
2527   // Usage counts
2528   size_t used_total = 0, unused_total = 0, identity_used_total = 0;
2529   for (RefsMap::Entry* ref = refs_->Start(); ref != nullptr;
2530        ref = refs_->Next(ref)) {
2531     switch (ref->value->used_status) {
2532       case ObjectData::Usage::kUnused:
2533         ++unused_total;
2534         break;
2535       case ObjectData::Usage::kOnlyIdentityUsed:
2536         ++identity_used_total;
2537         break;
2538       case ObjectData::Usage::kDataUsed:
2539         ++used_total;
2540         break;
2541     }
2542   }
2543 
2544   // Ref types analysis
2545   TRACE_BROKER_MEMORY(
2546       this, "Refs: " << refs_->occupancy() << "; data used: " << used_total
2547                      << "; only identity used: " << identity_used_total
2548                      << "; unused: " << unused_total);
2549   size_t used_smis = 0, unused_smis = 0, identity_used_smis = 0;
2550   size_t used[LAST_TYPE + 1] = {0};
2551   size_t unused[LAST_TYPE + 1] = {0};
2552   size_t identity_used[LAST_TYPE + 1] = {0};
2553   for (RefsMap::Entry* ref = refs_->Start(); ref != nullptr;
2554        ref = refs_->Next(ref)) {
2555     if (ref->value->is_smi()) {
2556       switch (ref->value->used_status) {
2557         case ObjectData::Usage::kUnused:
2558           ++unused_smis;
2559           break;
2560         case ObjectData::Usage::kOnlyIdentityUsed:
2561           ++identity_used_smis;
2562           break;
2563         case ObjectData::Usage::kDataUsed:
2564           ++used_smis;
2565           break;
2566       }
2567     } else {
2568       InstanceType instance_type;
2569       if (ref->value->should_access_heap()) {
2570         instance_type = Handle<HeapObject>::cast(ref->value->object())
2571                             ->map()
2572                             .instance_type();
2573       } else {
2574         instance_type = ref->value->AsHeapObject()->GetMapInstanceType();
2575       }
2576       CHECK_LE(FIRST_TYPE, instance_type);
2577       CHECK_LE(instance_type, LAST_TYPE);
2578       switch (ref->value->used_status) {
2579         case ObjectData::Usage::kUnused:
2580           ++unused[instance_type];
2581           break;
2582         case ObjectData::Usage::kOnlyIdentityUsed:
2583           ++identity_used[instance_type];
2584           break;
2585         case ObjectData::Usage::kDataUsed:
2586           ++used[instance_type];
2587           break;
2588       }
2589     }
2590   }
2591 
2592   TRACE_BROKER_MEMORY(
2593       this, "Smis: " << used_smis + identity_used_smis + unused_smis
2594                      << "; data used: " << used_smis << "; only identity used: "
2595                      << identity_used_smis << "; unused: " << unused_smis);
2596   for (uint16_t i = FIRST_TYPE; i <= LAST_TYPE; ++i) {
2597     size_t total = used[i] + identity_used[i] + unused[i];
2598     if (total == 0) continue;
2599     TRACE_BROKER_MEMORY(
2600         this, InstanceType(i) << ": " << total << "; data used: " << used[i]
2601                               << "; only identity used: " << identity_used[i]
2602                               << "; unused: " << unused[i]);
2603   }
2604 }
2605 #endif  // DEBUG
2606 
Retire()2607 void JSHeapBroker::Retire() {
2608   CHECK_EQ(mode_, kSerialized);
2609   TRACE(this, "Retiring");
2610   mode_ = kRetired;
2611 
2612 #ifdef DEBUG
2613   PrintRefsAnalysis();
2614 #endif  // DEBUG
2615 }
2616 
SetTargetNativeContextRef(Handle<NativeContext> native_context)2617 void JSHeapBroker::SetTargetNativeContextRef(
2618     Handle<NativeContext> native_context) {
2619   // The MapData constructor uses {target_native_context_}. This creates a
2620   // benign cycle that we break by setting {target_native_context_} right before
2621   // starting to serialize (thus creating dummy data), and then again properly
2622   // right after.
2623   DCHECK((mode() == kDisabled && !target_native_context_.has_value()) ||
2624          (mode() == kSerializing &&
2625           target_native_context_->object().equals(native_context) &&
2626           target_native_context_->data_->kind() == kUnserializedHeapObject));
2627   target_native_context_ = NativeContextRef(this, native_context);
2628 }
2629 
CollectArrayAndObjectPrototypes()2630 void JSHeapBroker::CollectArrayAndObjectPrototypes() {
2631   DisallowHeapAllocation no_gc;
2632   CHECK_EQ(mode(), kSerializing);
2633   CHECK(array_and_object_prototypes_.empty());
2634 
2635   Object maybe_context = isolate()->heap()->native_contexts_list();
2636   while (!maybe_context.IsUndefined(isolate())) {
2637     Context context = Context::cast(maybe_context);
2638     Object array_prot = context.get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
2639     Object object_prot = context.get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX);
2640     array_and_object_prototypes_.emplace(JSObject::cast(array_prot), isolate());
2641     array_and_object_prototypes_.emplace(JSObject::cast(object_prot),
2642                                          isolate());
2643     maybe_context = context.next_context_link();
2644   }
2645 
2646   CHECK(!array_and_object_prototypes_.empty());
2647 }
2648 
GetTypedArrayStringTag(ElementsKind kind)2649 StringRef JSHeapBroker::GetTypedArrayStringTag(ElementsKind kind) {
2650   DCHECK(IsTypedArrayElementsKind(kind));
2651   switch (kind) {
2652 #define TYPED_ARRAY_STRING_TAG(Type, type, TYPE, ctype) \
2653   case ElementsKind::TYPE##_ELEMENTS:                   \
2654     return StringRef(this, isolate()->factory()->Type##Array_string());
2655     TYPED_ARRAYS(TYPED_ARRAY_STRING_TAG)
2656 #undef TYPED_ARRAY_STRING_TAG
2657     default:
2658       UNREACHABLE();
2659   }
2660 }
2661 
ShouldBeSerializedForCompilation(const SharedFunctionInfoRef & shared,const FeedbackVectorRef & feedback,const HintsVector & arguments) const2662 bool JSHeapBroker::ShouldBeSerializedForCompilation(
2663     const SharedFunctionInfoRef& shared, const FeedbackVectorRef& feedback,
2664     const HintsVector& arguments) const {
2665   if (serialized_functions_.size() >= kMaxSerializedFunctionsCacheSize) {
2666     TRACE_BROKER_MISSING(this,
2667                          "opportunity - serialized functions cache is full.");
2668     return false;
2669   }
2670   SerializedFunction function{shared, feedback};
2671   auto matching_functions = serialized_functions_.equal_range(function);
2672   return std::find_if(matching_functions.first, matching_functions.second,
2673                       [&arguments](const auto& entry) {
2674                         return entry.second == arguments;
2675                       }) == matching_functions.second;
2676 }
2677 
SetSerializedForCompilation(const SharedFunctionInfoRef & shared,const FeedbackVectorRef & feedback,const HintsVector & arguments)2678 void JSHeapBroker::SetSerializedForCompilation(
2679     const SharedFunctionInfoRef& shared, const FeedbackVectorRef& feedback,
2680     const HintsVector& arguments) {
2681   SerializedFunction function{shared, feedback};
2682   serialized_functions_.insert({function, arguments});
2683   TRACE(this, "Set function " << shared << " with " << feedback
2684                               << " as serialized for compilation");
2685 }
2686 
IsSerializedForCompilation(const SharedFunctionInfoRef & shared,const FeedbackVectorRef & feedback) const2687 bool JSHeapBroker::IsSerializedForCompilation(
2688     const SharedFunctionInfoRef& shared,
2689     const FeedbackVectorRef& feedback) const {
2690   if (mode() == kDisabled) return true;
2691 
2692   SerializedFunction function = {shared, feedback};
2693   return serialized_functions_.find(function) != serialized_functions_.end();
2694 }
2695 
IsArrayOrObjectPrototype(const JSObjectRef & object) const2696 bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
2697   if (mode() == kDisabled) {
2698     return isolate()->IsInAnyContext(*object.object(),
2699                                      Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
2700            isolate()->IsInAnyContext(*object.object(),
2701                                      Context::INITIAL_OBJECT_PROTOTYPE_INDEX);
2702   }
2703   CHECK(!array_and_object_prototypes_.empty());
2704   return array_and_object_prototypes_.find(object.object()) !=
2705          array_and_object_prototypes_.end();
2706 }
2707 
InitializeAndStartSerializing(Handle<NativeContext> native_context)2708 void JSHeapBroker::InitializeAndStartSerializing(
2709     Handle<NativeContext> native_context) {
2710   TraceScope tracer(this, "JSHeapBroker::InitializeAndStartSerializing");
2711 
2712   CHECK_EQ(mode_, kDisabled);
2713   mode_ = kSerializing;
2714 
2715   // Throw away the dummy data that we created while disabled.
2716   refs_->Clear();
2717   refs_ = nullptr;
2718 
2719   refs_ =
2720       zone()->New<RefsMap>(kInitialRefsBucketCount, AddressMatcher(), zone());
2721 
2722   SetTargetNativeContextRef(native_context);
2723   target_native_context().Serialize();
2724 
2725   CollectArrayAndObjectPrototypes();
2726 
2727   Factory* const f = isolate()->factory();
2728   {
2729     ObjectData* data;
2730     data = GetOrCreateData(f->array_buffer_detaching_protector());
2731     if (!data->should_access_heap()) data->AsPropertyCell()->Serialize(this);
2732     data = GetOrCreateData(f->array_constructor_protector());
2733     if (!data->should_access_heap()) data->AsPropertyCell()->Serialize(this);
2734     data = GetOrCreateData(f->array_iterator_protector());
2735     if (!data->should_access_heap()) data->AsPropertyCell()->Serialize(this);
2736     data = GetOrCreateData(f->array_species_protector());
2737     if (!data->should_access_heap()) data->AsPropertyCell()->Serialize(this);
2738     data = GetOrCreateData(f->no_elements_protector());
2739     if (!data->should_access_heap()) data->AsPropertyCell()->Serialize(this);
2740     data = GetOrCreateData(f->promise_hook_protector());
2741     if (!data->should_access_heap()) data->AsPropertyCell()->Serialize(this);
2742     data = GetOrCreateData(f->promise_species_protector());
2743     if (!data->should_access_heap()) data->AsPropertyCell()->Serialize(this);
2744     data = GetOrCreateData(f->promise_then_protector());
2745     if (!data->should_access_heap()) data->AsPropertyCell()->Serialize(this);
2746     data = GetOrCreateData(f->string_length_protector());
2747     if (!data->should_access_heap()) data->AsPropertyCell()->Serialize(this);
2748   }
2749   GetOrCreateData(f->many_closures_cell());
2750   GetOrCreateData(
2751       CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs, kArgvOnStack, true));
2752 
2753   TRACE(this, "Finished serializing standard objects");
2754 }
2755 
2756 // clang-format off
GetOrCreateData(Handle<Object> object)2757 ObjectData* JSHeapBroker::GetOrCreateData(Handle<Object> object) {
2758   RefsMap::Entry* entry = refs_->LookupOrInsert(object.address());
2759   ObjectData* object_data = entry->value;
2760 
2761   if (object_data == nullptr) {
2762     ObjectData** data_storage = &(entry->value);
2763     // TODO(neis): Remove these Allow* once we serialize everything upfront.
2764     AllowHandleDereference handle_dereference;
2765     if (object->IsSmi()) {
2766       object_data = zone()->New<ObjectData>(this, data_storage, object, kSmi);
2767     } else if (IsReadOnlyHeapObject(*object)) {
2768       object_data = zone()->New<ObjectData>(this, data_storage, object,
2769                                             kUnserializedReadOnlyHeapObject);
2770 // TODO(solanes, v8:10866): Remove the if/else in this macro once we remove the
2771 // FLAG_turbo_direct_heap_access.
2772 #define CREATE_DATA_FOR_DIRECT_READ(name)                                  \
2773     } else if (object->Is##name()) {                                       \
2774       if (FLAG_turbo_direct_heap_access) {                                 \
2775         object_data = zone()->New<ObjectData>(                             \
2776           this, data_storage, object, kNeverSerializedHeapObject);         \
2777       } else {                                                             \
2778         CHECK_EQ(mode(), kSerializing);                                    \
2779         AllowHandleAllocation handle_allocation;                           \
2780         object_data = zone()->New<name##Data>(this, data_storage,          \
2781                                               Handle<name>::cast(object)); \
2782       }
2783     HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(CREATE_DATA_FOR_DIRECT_READ)
2784 #undef CREATE_DATA_FOR_DIRECT_READ
2785 #define CREATE_DATA_FOR_SERIALIZATION(name)                     \
2786     } else if (object->Is##name()) {                            \
2787       CHECK_EQ(mode(), kSerializing);                           \
2788       AllowHandleAllocation handle_allocation;                  \
2789       object_data = zone()->New<name##Data>(this, data_storage, \
2790                                             Handle<name>::cast(object));
2791     HEAP_BROKER_SERIALIZED_OBJECT_LIST(CREATE_DATA_FOR_SERIALIZATION)
2792 #undef CREATE_DATA_FOR_SERIALIZATION
2793     } else {
2794       UNREACHABLE();
2795     }
2796     // At this point the entry pointer is not guaranteed to be valid as
2797     // the refs_ hash hable could be resized by one of the constructors above.
2798     DCHECK_EQ(object_data, refs_->Lookup(object.address())->value);
2799   }
2800   return object_data;
2801 }
2802 // clang-format on
2803 
GetOrCreateData(Object object)2804 ObjectData* JSHeapBroker::GetOrCreateData(Object object) {
2805   return GetOrCreateData(CanonicalPersistentHandle(object));
2806 }
2807 
2808 #define DEFINE_IS_AND_AS(Name)                                    \
2809   bool ObjectRef::Is##Name() const { return data()->Is##Name(); } \
2810   Name##Ref ObjectRef::As##Name() const {                         \
2811     DCHECK(Is##Name());                                           \
2812     return Name##Ref(broker(), data());                           \
2813   }
2814 HEAP_BROKER_SERIALIZED_OBJECT_LIST(DEFINE_IS_AND_AS)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DEFINE_IS_AND_AS)2815 HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DEFINE_IS_AND_AS)
2816 #undef DEFINE_IS_AND_AS
2817 
2818 bool ObjectRef::IsSmi() const { return data()->is_smi(); }
2819 
AsSmi() const2820 int ObjectRef::AsSmi() const {
2821   DCHECK(IsSmi());
2822   // Handle-dereference is always allowed for Handle<Smi>.
2823   return Handle<Smi>::cast(object())->value();
2824 }
2825 
GetObjectCreateMap() const2826 base::Optional<MapRef> JSObjectRef::GetObjectCreateMap() const {
2827   if (data_->should_access_heap()) {
2828     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
2829                                                           broker()->mode());
2830     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
2831                                                             broker()->mode());
2832     AllowHeapAllocationIfNeeded allow_heap_allocation(data()->kind(),
2833                                                       broker()->mode());
2834     Handle<Map> instance_map;
2835     if (Map::TryGetObjectCreateMap(broker()->isolate(), object())
2836             .ToHandle(&instance_map)) {
2837       return MapRef(broker(), instance_map);
2838     } else {
2839       return base::Optional<MapRef>();
2840     }
2841   }
2842   ObjectData* map_data = data()->AsJSObject()->object_create_map(broker());
2843   if (map_data == nullptr) return base::Optional<MapRef>();
2844   if (map_data->should_access_heap()) {
2845     return MapRef(broker(), map_data->object());
2846   }
2847   return MapRef(broker(), map_data->AsMap());
2848 }
2849 
2850 #define DEF_TESTER(Type, ...)                              \
2851   bool MapRef::Is##Type##Map() const {                     \
2852     return InstanceTypeChecker::Is##Type(instance_type()); \
2853   }
INSTANCE_TYPE_CHECKERS(DEF_TESTER)2854 INSTANCE_TYPE_CHECKERS(DEF_TESTER)
2855 #undef DEF_TESTER
2856 
2857 base::Optional<MapRef> MapRef::AsElementsKind(ElementsKind kind) const {
2858   if (data_->should_access_heap()) {
2859     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
2860                                                           broker()->mode());
2861     AllowHeapAllocationIfNeeded allow_heap_allocation(data()->kind(),
2862                                                       broker()->mode());
2863     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
2864                                                             broker()->mode());
2865     return MapRef(broker(),
2866                   Map::AsElementsKind(broker()->isolate(), object(), kind));
2867   }
2868   if (kind == elements_kind()) return *this;
2869   const ZoneVector<ObjectData*>& elements_kind_generalizations =
2870       data()->AsMap()->elements_kind_generalizations();
2871   for (auto data : elements_kind_generalizations) {
2872     MapRef map(broker(), data);
2873     if (map.elements_kind() == kind) return map;
2874   }
2875   return base::Optional<MapRef>();
2876 }
2877 
SerializeForElementLoad()2878 void MapRef::SerializeForElementLoad() {
2879   if (data()->should_access_heap()) return;
2880   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2881   data()->AsMap()->SerializeForElementLoad(broker());
2882 }
2883 
SerializeForElementStore()2884 void MapRef::SerializeForElementStore() {
2885   if (data()->should_access_heap()) return;
2886   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2887   data()->AsMap()->SerializeForElementStore(broker());
2888 }
2889 
2890 namespace {
2891 // This helper function has two modes. If {prototype_maps} is nullptr, the
2892 // prototype chain is serialized as necessary to determine the result.
2893 // Otherwise, the heap is untouched and the encountered prototypes are pushed
2894 // onto {prototype_maps}.
HasOnlyStablePrototypesWithFastElementsHelper(JSHeapBroker * broker,MapRef const & map,ZoneVector<MapRef> * prototype_maps)2895 bool HasOnlyStablePrototypesWithFastElementsHelper(
2896     JSHeapBroker* broker, MapRef const& map,
2897     ZoneVector<MapRef>* prototype_maps) {
2898   for (MapRef prototype_map = map;;) {
2899     if (prototype_maps == nullptr) prototype_map.SerializePrototype();
2900     prototype_map = prototype_map.prototype().AsHeapObject().map();
2901     if (prototype_map.oddball_type() == OddballType::kNull) return true;
2902     if (!map.prototype().IsJSObject() || !prototype_map.is_stable() ||
2903         !IsFastElementsKind(prototype_map.elements_kind())) {
2904       return false;
2905     }
2906     if (prototype_maps != nullptr) prototype_maps->push_back(prototype_map);
2907   }
2908 }
2909 }  // namespace
2910 
SerializeForElementLoad(JSHeapBroker * broker)2911 void MapData::SerializeForElementLoad(JSHeapBroker* broker) {
2912   if (serialized_for_element_load_) return;
2913   serialized_for_element_load_ = true;
2914 
2915   TraceScope tracer(broker, this, "MapData::SerializeForElementLoad");
2916   SerializePrototype(broker);
2917 }
2918 
SerializeForElementStore(JSHeapBroker * broker)2919 void MapData::SerializeForElementStore(JSHeapBroker* broker) {
2920   if (serialized_for_element_store_) return;
2921   serialized_for_element_store_ = true;
2922 
2923   TraceScope tracer(broker, this, "MapData::SerializeForElementStore");
2924   HasOnlyStablePrototypesWithFastElementsHelper(broker, MapRef(broker, this),
2925                                                 nullptr);
2926 }
2927 
HasOnlyStablePrototypesWithFastElements(ZoneVector<MapRef> * prototype_maps)2928 bool MapRef::HasOnlyStablePrototypesWithFastElements(
2929     ZoneVector<MapRef>* prototype_maps) {
2930   for (MapRef prototype_map = *this;;) {
2931     if (prototype_maps == nullptr) prototype_map.SerializePrototype();
2932     prototype_map = prototype_map.prototype().AsHeapObject().map();
2933     if (prototype_map.oddball_type() == OddballType::kNull) return true;
2934     if (!prototype().IsJSObject() || !prototype_map.is_stable() ||
2935         !IsFastElementsKind(prototype_map.elements_kind())) {
2936       return false;
2937     }
2938     if (prototype_maps != nullptr) prototype_maps->push_back(prototype_map);
2939   }
2940 }
2941 
supports_fast_array_iteration() const2942 bool MapRef::supports_fast_array_iteration() const {
2943   if (data_->should_access_heap()) {
2944     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
2945                                                             broker()->mode());
2946     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
2947                                                           broker()->mode());
2948     return SupportsFastArrayIteration(broker()->isolate(), object());
2949   }
2950   return data()->AsMap()->supports_fast_array_iteration();
2951 }
2952 
supports_fast_array_resize() const2953 bool MapRef::supports_fast_array_resize() const {
2954   if (data_->should_access_heap()) {
2955     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
2956                                                             broker()->mode());
2957     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
2958                                                           broker()->mode());
2959     return SupportsFastArrayResize(broker()->isolate(), object());
2960   }
2961   return data()->AsMap()->supports_fast_array_resize();
2962 }
2963 
InitialMapInstanceSizeWithMinSlack() const2964 int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const {
2965   if (data_->should_access_heap()) {
2966     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
2967                                                             broker()->mode());
2968     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
2969                                                           broker()->mode());
2970     return object()->ComputeInstanceSizeWithMinSlack(broker()->isolate());
2971   }
2972   return data()->AsJSFunction()->initial_map_instance_size_with_min_slack();
2973 }
2974 
oddball_type() const2975 OddballType MapRef::oddball_type() const {
2976   if (instance_type() != ODDBALL_TYPE) {
2977     return OddballType::kNone;
2978   }
2979   Factory* f = broker()->isolate()->factory();
2980   if (equals(MapRef(broker(), f->undefined_map()))) {
2981     return OddballType::kUndefined;
2982   }
2983   if (equals(MapRef(broker(), f->null_map()))) {
2984     return OddballType::kNull;
2985   }
2986   if (equals(MapRef(broker(), f->boolean_map()))) {
2987     return OddballType::kBoolean;
2988   }
2989   if (equals(MapRef(broker(), f->the_hole_map()))) {
2990     return OddballType::kHole;
2991   }
2992   if (equals(MapRef(broker(), f->uninitialized_map()))) {
2993     return OddballType::kUninitialized;
2994   }
2995   DCHECK(equals(MapRef(broker(), f->termination_exception_map())) ||
2996          equals(MapRef(broker(), f->arguments_marker_map())) ||
2997          equals(MapRef(broker(), f->optimized_out_map())) ||
2998          equals(MapRef(broker(), f->stale_register_map())));
2999   return OddballType::kOther;
3000 }
3001 
GetClosureFeedbackCell(int index) const3002 FeedbackCellRef FeedbackVectorRef::GetClosureFeedbackCell(int index) const {
3003   if (data_->should_access_heap()) {
3004     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3005                                                           broker()->mode());
3006     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3007                                                             broker()->mode());
3008     return FeedbackCellRef(broker(), object()->GetClosureFeedbackCell(index));
3009   }
3010 
3011   return FeedbackCellRef(
3012       broker(),
3013       data()->AsFeedbackVector()->GetClosureFeedbackCell(broker(), index));
3014 }
3015 
RawFastDoublePropertyAt(FieldIndex index) const3016 double JSObjectRef::RawFastDoublePropertyAt(FieldIndex index) const {
3017   if (data_->should_access_heap()) {
3018     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3019                                                             broker()->mode());
3020     return object()->RawFastDoublePropertyAt(index);
3021   }
3022   JSObjectData* object_data = data()->AsJSObject();
3023   CHECK(index.is_inobject());
3024   return object_data->GetInobjectField(index.property_index()).AsDouble();
3025 }
3026 
RawFastDoublePropertyAsBitsAt(FieldIndex index) const3027 uint64_t JSObjectRef::RawFastDoublePropertyAsBitsAt(FieldIndex index) const {
3028   if (data_->should_access_heap()) {
3029     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3030                                                             broker()->mode());
3031     return object()->RawFastDoublePropertyAsBitsAt(index);
3032   }
3033   JSObjectData* object_data = data()->AsJSObject();
3034   CHECK(index.is_inobject());
3035   return object_data->GetInobjectField(index.property_index()).AsBitsOfDouble();
3036 }
3037 
RawFastPropertyAt(FieldIndex index) const3038 ObjectRef JSObjectRef::RawFastPropertyAt(FieldIndex index) const {
3039   if (data_->should_access_heap()) {
3040     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3041                                                           broker()->mode());
3042     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3043                                                             broker()->mode());
3044     return ObjectRef(broker(), broker()->CanonicalPersistentHandle(
3045                                    object()->RawFastPropertyAt(index)));
3046   }
3047   JSObjectData* object_data = data()->AsJSObject();
3048   CHECK(index.is_inobject());
3049   return ObjectRef(
3050       broker(),
3051       object_data->GetInobjectField(index.property_index()).AsObject());
3052 }
3053 
IsFastLiteral() const3054 bool AllocationSiteRef::IsFastLiteral() const {
3055   if (data_->should_access_heap()) {
3056     CHECK_NE(data_->kind(), ObjectDataKind::kNeverSerializedHeapObject);
3057     AllowHeapAllocationIfNeeded allow_heap_allocation(
3058         data()->kind(), broker()->mode());  // For TryMigrateInstance.
3059     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3060                                                           broker()->mode());
3061     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3062                                                             broker()->mode());
3063     return IsInlinableFastLiteral(
3064         handle(object()->boilerplate(), broker()->isolate()));
3065   }
3066   return data()->AsAllocationSite()->IsFastLiteral();
3067 }
3068 
SerializeBoilerplate()3069 void AllocationSiteRef::SerializeBoilerplate() {
3070   if (data_->should_access_heap()) return;
3071   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
3072   data()->AsAllocationSite()->SerializeBoilerplate(broker());
3073 }
3074 
SerializeElements()3075 void JSObjectRef::SerializeElements() {
3076   if (data_->should_access_heap()) return;
3077   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
3078   data()->AsJSObject()->SerializeElements(broker());
3079 }
3080 
EnsureElementsTenured()3081 void JSObjectRef::EnsureElementsTenured() {
3082   if (data_->should_access_heap()) {
3083     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3084                                                           broker()->mode());
3085     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3086                                                             broker()->mode());
3087     AllowHeapAllocationIfNeeded allow_heap_allocation(data()->kind(),
3088                                                       broker()->mode());
3089 
3090     Handle<FixedArrayBase> object_elements = elements().object();
3091     if (ObjectInYoungGeneration(*object_elements)) {
3092       // If we would like to pretenure a fixed cow array, we must ensure that
3093       // the array is already in old space, otherwise we'll create too many
3094       // old-to-new-space pointers (overflowing the store buffer).
3095       object_elements =
3096           broker()->isolate()->factory()->CopyAndTenureFixedCOWArray(
3097               Handle<FixedArray>::cast(object_elements));
3098       object()->set_elements(*object_elements);
3099     }
3100     return;
3101   }
3102   CHECK(data()->AsJSObject()->cow_or_empty_elements_tenured());
3103 }
3104 
GetFieldIndexFor(InternalIndex descriptor_index) const3105 FieldIndex MapRef::GetFieldIndexFor(InternalIndex descriptor_index) const {
3106   if (data_->should_access_heap()) {
3107     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3108                                                             broker()->mode());
3109     return FieldIndex::ForDescriptor(*object(), descriptor_index);
3110   }
3111   DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
3112   return descriptors->contents().at(descriptor_index.as_int()).field_index;
3113 }
3114 
GetInObjectPropertyOffset(int i) const3115 int MapRef::GetInObjectPropertyOffset(int i) const {
3116   if (data_->should_access_heap()) {
3117     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3118                                                             broker()->mode());
3119     return object()->GetInObjectPropertyOffset(i);
3120   }
3121   return (GetInObjectPropertiesStartInWords() + i) * kTaggedSize;
3122 }
3123 
GetPropertyDetails(InternalIndex descriptor_index) const3124 PropertyDetails MapRef::GetPropertyDetails(
3125     InternalIndex descriptor_index) const {
3126   if (data_->should_access_heap()) {
3127     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3128                                                             broker()->mode());
3129     return object()
3130         ->instance_descriptors(kRelaxedLoad)
3131         .GetDetails(descriptor_index);
3132   }
3133   DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
3134   return descriptors->contents().at(descriptor_index.as_int()).details;
3135 }
3136 
GetPropertyKey(InternalIndex descriptor_index) const3137 NameRef MapRef::GetPropertyKey(InternalIndex descriptor_index) const {
3138   if (data_->should_access_heap()) {
3139     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3140                                                           broker()->mode());
3141     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3142                                                             broker()->mode());
3143     return NameRef(broker(), broker()->CanonicalPersistentHandle(
3144                                  object()
3145                                      ->instance_descriptors(kRelaxedLoad)
3146                                      .GetKey(descriptor_index)));
3147   }
3148   DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
3149   return NameRef(broker(),
3150                  descriptors->contents().at(descriptor_index.as_int()).key);
3151 }
3152 
IsFixedCowArrayMap() const3153 bool MapRef::IsFixedCowArrayMap() const {
3154   Handle<Map> fixed_cow_array_map =
3155       ReadOnlyRoots(broker()->isolate()).fixed_cow_array_map_handle();
3156   return equals(MapRef(broker(), fixed_cow_array_map));
3157 }
3158 
IsPrimitiveMap() const3159 bool MapRef::IsPrimitiveMap() const {
3160   return instance_type() <= LAST_PRIMITIVE_HEAP_OBJECT_TYPE;
3161 }
3162 
FindFieldOwner(InternalIndex descriptor_index) const3163 MapRef MapRef::FindFieldOwner(InternalIndex descriptor_index) const {
3164   if (data_->should_access_heap()) {
3165     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3166                                                           broker()->mode());
3167     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3168                                                             broker()->mode());
3169     Handle<Map> owner(
3170         object()->FindFieldOwner(broker()->isolate(), descriptor_index),
3171         broker()->isolate());
3172     return MapRef(broker(), owner);
3173   }
3174   DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
3175   return MapRef(
3176       broker(),
3177       descriptors->contents().at(descriptor_index.as_int()).field_owner);
3178 }
3179 
GetFieldType(InternalIndex descriptor_index) const3180 ObjectRef MapRef::GetFieldType(InternalIndex descriptor_index) const {
3181   if (data_->should_access_heap()) {
3182     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3183                                                           broker()->mode());
3184     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3185                                                             broker()->mode());
3186     Handle<FieldType> field_type(object()
3187                                      ->instance_descriptors(kRelaxedLoad)
3188                                      .GetFieldType(descriptor_index),
3189                                  broker()->isolate());
3190     return ObjectRef(broker(), field_type);
3191   }
3192   DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
3193   return ObjectRef(
3194       broker(),
3195       descriptors->contents().at(descriptor_index.as_int()).field_type);
3196 }
3197 
IsUnboxedDoubleField(InternalIndex descriptor_index) const3198 bool MapRef::IsUnboxedDoubleField(InternalIndex descriptor_index) const {
3199   if (data_->should_access_heap()) {
3200     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3201                                                             broker()->mode());
3202     return object()->IsUnboxedDoubleField(
3203         FieldIndex::ForDescriptor(*object(), descriptor_index));
3204   }
3205   DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
3206   return descriptors->contents()
3207       .at(descriptor_index.as_int())
3208       .is_unboxed_double_field;
3209 }
3210 
GetFirstChar()3211 uint16_t StringRef::GetFirstChar() {
3212   if (data_->should_access_heap()) {
3213     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3214                                                             broker()->mode());
3215     return object()->Get(0);
3216   }
3217   return data()->AsString()->first_char();
3218 }
3219 
ToNumber()3220 base::Optional<double> StringRef::ToNumber() {
3221   if (data_->should_access_heap()) {
3222     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3223                                                             broker()->mode());
3224     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3225                                                           broker()->mode());
3226     return StringToDouble(object());
3227   }
3228   return data()->AsString()->to_number();
3229 }
3230 
constants_elements_length() const3231 int ArrayBoilerplateDescriptionRef::constants_elements_length() const {
3232   if (data_->should_access_heap()) {
3233     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3234                                                             broker()->mode());
3235     return object()->constant_elements().length();
3236   }
3237   return data()->AsArrayBoilerplateDescription()->constants_elements_length();
3238 }
3239 
get(int i) const3240 ObjectRef FixedArrayRef::get(int i) const {
3241   if (data_->should_access_heap()) {
3242     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3243                                                           broker()->mode());
3244     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3245                                                             broker()->mode());
3246     return ObjectRef(broker(),
3247                      broker()->CanonicalPersistentHandle(object()->get(i)));
3248   }
3249   return ObjectRef(broker(), data()->AsFixedArray()->Get(i));
3250 }
3251 
get(int i) const3252 Float64 FixedDoubleArrayRef::get(int i) const {
3253   if (data_->should_access_heap()) {
3254     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3255                                                             broker()->mode());
3256     return Float64::FromBits(object()->get_representation(i));
3257   } else {
3258     return data()->AsFixedDoubleArray()->Get(i);
3259   }
3260 }
3261 
get(int index) const3262 uint8_t BytecodeArrayRef::get(int index) const { return object()->get(index); }
3263 
GetFirstBytecodeAddress() const3264 Address BytecodeArrayRef::GetFirstBytecodeAddress() const {
3265   return object()->GetFirstBytecodeAddress();
3266 }
3267 
GetConstantAtIndex(int index) const3268 Handle<Object> BytecodeArrayRef::GetConstantAtIndex(int index) const {
3269   if (data_->should_access_heap()) {
3270     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3271                                                           broker()->mode());
3272     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3273                                                             broker()->mode());
3274     return broker()->CanonicalPersistentHandle(
3275         object()->constant_pool().get(index));
3276   }
3277   return data()->AsBytecodeArray()->GetConstantAtIndex(index,
3278                                                        broker()->isolate());
3279 }
3280 
IsConstantAtIndexSmi(int index) const3281 bool BytecodeArrayRef::IsConstantAtIndexSmi(int index) const {
3282   if (data_->should_access_heap()) {
3283     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3284                                                           broker()->mode());
3285     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3286                                                             broker()->mode());
3287     return object()->constant_pool().get(index).IsSmi();
3288   }
3289   return data()->AsBytecodeArray()->IsConstantAtIndexSmi(index);
3290 }
3291 
GetConstantAtIndexAsSmi(int index) const3292 Smi BytecodeArrayRef::GetConstantAtIndexAsSmi(int index) const {
3293   if (data_->should_access_heap()) {
3294     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3295                                                           broker()->mode());
3296     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3297                                                             broker()->mode());
3298     return Smi::cast(object()->constant_pool().get(index));
3299   }
3300   return data()->AsBytecodeArray()->GetConstantAtIndexAsSmi(index);
3301 }
3302 
SerializeForCompilation()3303 void BytecodeArrayRef::SerializeForCompilation() {
3304   if (data_->should_access_heap()) return;
3305   data()->AsBytecodeArray()->SerializeForCompilation(broker());
3306 }
3307 
SourcePositionTable() const3308 Handle<ByteArray> BytecodeArrayRef::SourcePositionTable() const {
3309   return broker()->CanonicalPersistentHandle(object()->SourcePositionTable());
3310 }
3311 
handler_table_address() const3312 Address BytecodeArrayRef::handler_table_address() const {
3313   return reinterpret_cast<Address>(
3314       object()->handler_table().GetDataStartAddress());
3315 }
3316 
handler_table_size() const3317 int BytecodeArrayRef::handler_table_size() const {
3318   return object()->handler_table().length();
3319 }
3320 
3321 #define IF_ACCESS_FROM_HEAP_C(name)                                            \
3322   if (data_->should_access_heap()) {                                           \
3323     AllowHandleAllocationIfNeeded handle_allocation(data_->kind(),             \
3324                                                     broker()->mode());         \
3325     AllowHandleDereferenceIfNeeded allow_handle_dereference(data_->kind(),     \
3326                                                             broker()->mode()); \
3327     return object()->name();                                                   \
3328   }
3329 
3330 #define IF_ACCESS_FROM_HEAP(result, name)                                      \
3331   if (data_->should_access_heap()) {                                           \
3332     AllowHandleAllocationIfNeeded handle_allocation(data_->kind(),             \
3333                                                     broker()->mode());         \
3334     AllowHandleDereferenceIfNeeded handle_dereference(data_->kind(),           \
3335                                                       broker()->mode());       \
3336     return result##Ref(broker(),                                               \
3337                        broker()->CanonicalPersistentHandle(object()->name())); \
3338   }
3339 
3340 // Macros for definining a const getter that, depending on the data kind,
3341 // either looks into the heap or into the serialized data.
3342 #define BIMODAL_ACCESSOR(holder, result, name)                             \
3343   result##Ref holder##Ref::name() const {                                  \
3344     IF_ACCESS_FROM_HEAP(result, name);                                     \
3345     return result##Ref(broker(), ObjectRef::data()->As##holder()->name()); \
3346   }
3347 
3348 // Like above except that the result type is not an XYZRef.
3349 #define BIMODAL_ACCESSOR_C(holder, result, name)    \
3350   result holder##Ref::name() const {                \
3351     IF_ACCESS_FROM_HEAP_C(name);                    \
3352     return ObjectRef::data()->As##holder()->name(); \
3353   }
3354 
3355 // Like above but for BitFields.
3356 #define BIMODAL_ACCESSOR_B(holder, field, name, BitField)              \
3357   typename BitField::FieldType holder##Ref::name() const {             \
3358     IF_ACCESS_FROM_HEAP_C(name);                                       \
3359     return BitField::decode(ObjectRef::data()->As##holder()->field()); \
3360   }
3361 
3362 // Like IF_ACCESS_FROM_HEAP[_C] but we also allow direct heap access for
3363 // kSerialized only for methods that we identified to be safe.
3364 #define IF_ACCESS_FROM_HEAP_WITH_FLAG(result, name)                            \
3365   if (data_->should_access_heap() || FLAG_turbo_direct_heap_access) {          \
3366     AllowHandleAllocationIfNeeded handle_allocation(                           \
3367         data_->kind(), broker()->mode(), FLAG_turbo_direct_heap_access);       \
3368     AllowHandleDereferenceIfNeeded allow_handle_dereference(                   \
3369         data_->kind(), broker()->mode(), FLAG_turbo_direct_heap_access);       \
3370     return result##Ref(broker(),                                               \
3371                        broker()->CanonicalPersistentHandle(object()->name())); \
3372   }
3373 #define IF_ACCESS_FROM_HEAP_WITH_FLAG_C(name)                            \
3374   if (data_->should_access_heap() || FLAG_turbo_direct_heap_access) {    \
3375     AllowHandleAllocationIfNeeded handle_allocation(                     \
3376         data_->kind(), broker()->mode(), FLAG_turbo_direct_heap_access); \
3377     AllowHandleDereferenceIfNeeded allow_handle_dereference(             \
3378         data_->kind(), broker()->mode(), FLAG_turbo_direct_heap_access); \
3379     return object()->name();                                             \
3380   }
3381 
3382 // Like BIMODAL_ACCESSOR[_C] except that we force a direct heap access if
3383 // FLAG_turbo_direct_heap_access is true (even for kSerialized). This is because
3384 // we identified the method to be safe to use direct heap access, but the
3385 // holder##Data class still needs to be serialized.
3386 #define BIMODAL_ACCESSOR_WITH_FLAG(holder, result, name)                   \
3387   result##Ref holder##Ref::name() const {                                  \
3388     IF_ACCESS_FROM_HEAP_WITH_FLAG(result, name);                           \
3389     return result##Ref(broker(), ObjectRef::data()->As##holder()->name()); \
3390   }
3391 #define BIMODAL_ACCESSOR_WITH_FLAG_C(holder, result, name) \
3392   result holder##Ref::name() const {                       \
3393     IF_ACCESS_FROM_HEAP_WITH_FLAG_C(name);                 \
3394     return ObjectRef::data()->As##holder()->name();        \
3395   }
3396 
BIMODAL_ACCESSOR(AllocationSite,Object,nested_site)3397 BIMODAL_ACCESSOR(AllocationSite, Object, nested_site)
3398 BIMODAL_ACCESSOR_C(AllocationSite, bool, CanInlineCall)
3399 BIMODAL_ACCESSOR_C(AllocationSite, bool, PointsToLiteral)
3400 BIMODAL_ACCESSOR_C(AllocationSite, ElementsKind, GetElementsKind)
3401 BIMODAL_ACCESSOR_C(AllocationSite, AllocationType, GetAllocationType)
3402 
3403 BIMODAL_ACCESSOR_C(BigInt, uint64_t, AsUint64)
3404 
3405 BIMODAL_ACCESSOR_C(BytecodeArray, int, register_count)
3406 BIMODAL_ACCESSOR_C(BytecodeArray, int, parameter_count)
3407 BIMODAL_ACCESSOR_C(BytecodeArray, interpreter::Register,
3408                    incoming_new_target_or_generator_register)
3409 
3410 BIMODAL_ACCESSOR_C(FeedbackVector, double, invocation_count)
3411 
3412 BIMODAL_ACCESSOR(HeapObject, Map, map)
3413 
3414 BIMODAL_ACCESSOR_C(HeapNumber, double, value)
3415 
3416 BIMODAL_ACCESSOR(JSArray, Object, length)
3417 
3418 BIMODAL_ACCESSOR(JSBoundFunction, JSReceiver, bound_target_function)
3419 BIMODAL_ACCESSOR(JSBoundFunction, Object, bound_this)
3420 BIMODAL_ACCESSOR(JSBoundFunction, FixedArray, bound_arguments)
3421 
3422 BIMODAL_ACCESSOR_C(JSDataView, size_t, byte_length)
3423 
3424 BIMODAL_ACCESSOR_C(JSFunction, bool, has_feedback_vector)
3425 BIMODAL_ACCESSOR_C(JSFunction, bool, has_initial_map)
3426 BIMODAL_ACCESSOR_C(JSFunction, bool, has_prototype)
3427 BIMODAL_ACCESSOR_C(JSFunction, bool, HasAttachedOptimizedCode)
3428 BIMODAL_ACCESSOR_C(JSFunction, bool, PrototypeRequiresRuntimeLookup)
3429 BIMODAL_ACCESSOR(JSFunction, Context, context)
3430 BIMODAL_ACCESSOR(JSFunction, NativeContext, native_context)
3431 BIMODAL_ACCESSOR(JSFunction, Map, initial_map)
3432 BIMODAL_ACCESSOR(JSFunction, Object, prototype)
3433 BIMODAL_ACCESSOR(JSFunction, SharedFunctionInfo, shared)
3434 BIMODAL_ACCESSOR(JSFunction, FeedbackCell, raw_feedback_cell)
3435 BIMODAL_ACCESSOR(JSFunction, FeedbackVector, feedback_vector)
3436 BIMODAL_ACCESSOR(JSFunction, Code, code)
3437 
3438 BIMODAL_ACCESSOR_C(JSGlobalObject, bool, IsDetached)
3439 
3440 BIMODAL_ACCESSOR_C(JSTypedArray, bool, is_on_heap)
3441 BIMODAL_ACCESSOR_C(JSTypedArray, size_t, length)
3442 BIMODAL_ACCESSOR(JSTypedArray, HeapObject, buffer)
3443 
3444 BIMODAL_ACCESSOR_B(Map, bit_field2, elements_kind, Map::Bits2::ElementsKindBits)
3445 BIMODAL_ACCESSOR_B(Map, bit_field3, is_dictionary_map,
3446                    Map::Bits3::IsDictionaryMapBit)
3447 BIMODAL_ACCESSOR_B(Map, bit_field3, is_deprecated, Map::Bits3::IsDeprecatedBit)
3448 BIMODAL_ACCESSOR_B(Map, bit_field3, NumberOfOwnDescriptors,
3449                    Map::Bits3::NumberOfOwnDescriptorsBits)
3450 BIMODAL_ACCESSOR_B(Map, bit_field3, is_migration_target,
3451                    Map::Bits3::IsMigrationTargetBit)
3452 BIMODAL_ACCESSOR_B(Map, bit_field3, is_extensible, Map::Bits3::IsExtensibleBit)
3453 BIMODAL_ACCESSOR_B(Map, bit_field, has_prototype_slot,
3454                    Map::Bits1::HasPrototypeSlotBit)
3455 BIMODAL_ACCESSOR_B(Map, bit_field, is_access_check_needed,
3456                    Map::Bits1::IsAccessCheckNeededBit)
3457 BIMODAL_ACCESSOR_B(Map, bit_field, is_callable, Map::Bits1::IsCallableBit)
3458 BIMODAL_ACCESSOR_B(Map, bit_field, has_indexed_interceptor,
3459                    Map::Bits1::HasIndexedInterceptorBit)
3460 BIMODAL_ACCESSOR_B(Map, bit_field, is_constructor, Map::Bits1::IsConstructorBit)
3461 BIMODAL_ACCESSOR_B(Map, bit_field, is_undetectable,
3462                    Map::Bits1::IsUndetectableBit)
3463 BIMODAL_ACCESSOR_C(Map, int, instance_size)
3464 BIMODAL_ACCESSOR_C(Map, int, NextFreePropertyIndex)
3465 BIMODAL_ACCESSOR_C(Map, int, UnusedPropertyFields)
3466 BIMODAL_ACCESSOR(Map, HeapObject, prototype)
3467 BIMODAL_ACCESSOR_C(Map, InstanceType, instance_type)
3468 BIMODAL_ACCESSOR(Map, Object, GetConstructor)
3469 BIMODAL_ACCESSOR(Map, HeapObject, GetBackPointer)
3470 BIMODAL_ACCESSOR_C(Map, bool, is_abandoned_prototype_map)
3471 
3472 BIMODAL_ACCESSOR_C(Code, unsigned, inlined_bytecode_size)
3473 
3474 #define DEF_NATIVE_CONTEXT_ACCESSOR(type, name) \
3475   BIMODAL_ACCESSOR(NativeContext, type, name)
3476 BROKER_NATIVE_CONTEXT_FIELDS(DEF_NATIVE_CONTEXT_ACCESSOR)
3477 #undef DEF_NATIVE_CONTEXT_ACCESSOR
3478 
3479 BIMODAL_ACCESSOR_C(ObjectBoilerplateDescription, int, size)
3480 
3481 BIMODAL_ACCESSOR(PropertyCell, Object, value)
3482 BIMODAL_ACCESSOR_C(PropertyCell, PropertyDetails, property_details)
3483 
3484 base::Optional<CallHandlerInfoRef> FunctionTemplateInfoRef::call_code() const {
3485   if (data_->should_access_heap()) {
3486     return CallHandlerInfoRef(broker(), broker()->CanonicalPersistentHandle(
3487                                             object()->call_code(kAcquireLoad)));
3488   }
3489   ObjectData* call_code = data()->AsFunctionTemplateInfo()->call_code();
3490   if (!call_code) return base::nullopt;
3491   return CallHandlerInfoRef(broker(), call_code);
3492 }
3493 
is_signature_undefined() const3494 bool FunctionTemplateInfoRef::is_signature_undefined() const {
3495   if (data_->should_access_heap()) {
3496     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3497                                                             broker()->mode());
3498     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3499                                                           broker()->mode());
3500 
3501     return object()->signature().IsUndefined(broker()->isolate());
3502   }
3503   return data()->AsFunctionTemplateInfo()->is_signature_undefined();
3504 }
3505 
has_call_code() const3506 bool FunctionTemplateInfoRef::has_call_code() const {
3507   if (data_->should_access_heap()) {
3508     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3509                                                             broker()->mode());
3510     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3511                                                           broker()->mode());
3512 
3513     CallOptimization call_optimization(broker()->isolate(), object());
3514     return call_optimization.is_simple_api_call();
3515   }
3516   return data()->AsFunctionTemplateInfo()->has_call_code();
3517 }
3518 
BIMODAL_ACCESSOR_C(FunctionTemplateInfo,bool,accept_any_receiver)3519 BIMODAL_ACCESSOR_C(FunctionTemplateInfo, bool, accept_any_receiver)
3520 
3521 HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType(
3522     MapRef receiver_map, SerializationPolicy policy) {
3523   const HolderLookupResult not_found;
3524 
3525   if (data_->should_access_heap()) {
3526     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3527                                                             broker()->mode());
3528     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3529                                                           broker()->mode());
3530 
3531     CallOptimization call_optimization(broker()->isolate(), object());
3532     Handle<Map> receiver_map_ref(receiver_map.object());
3533     if (!receiver_map_ref->IsJSReceiverMap() ||
3534         (receiver_map_ref->is_access_check_needed() &&
3535          !object()->accept_any_receiver())) {
3536       return not_found;
3537     }
3538 
3539     HolderLookupResult result;
3540     Handle<JSObject> holder = call_optimization.LookupHolderOfExpectedType(
3541         receiver_map_ref, &result.lookup);
3542 
3543     switch (result.lookup) {
3544       case CallOptimization::kHolderFound:
3545         result.holder = JSObjectRef(broker(), holder);
3546         break;
3547       default:
3548         DCHECK_EQ(result.holder, base::nullopt);
3549         break;
3550     }
3551     return result;
3552   }
3553 
3554   FunctionTemplateInfoData* fti_data = data()->AsFunctionTemplateInfo();
3555   KnownReceiversMap::iterator lookup_it =
3556       fti_data->known_receivers().find(receiver_map.data());
3557   if (lookup_it != fti_data->known_receivers().cend()) {
3558     return lookup_it->second;
3559   }
3560   if (policy == SerializationPolicy::kAssumeSerialized) {
3561     TRACE_BROKER_MISSING(broker(),
3562                          "holder for receiver with map " << receiver_map);
3563     return not_found;
3564   }
3565   if (!receiver_map.IsJSReceiverMap() ||
3566       (receiver_map.is_access_check_needed() && !accept_any_receiver())) {
3567     fti_data->known_receivers().insert({receiver_map.data(), not_found});
3568     return not_found;
3569   }
3570 
3571   HolderLookupResult result;
3572   CallOptimization call_optimization(broker()->isolate(), object());
3573   Handle<JSObject> holder = call_optimization.LookupHolderOfExpectedType(
3574       receiver_map.object(), &result.lookup);
3575 
3576   switch (result.lookup) {
3577     case CallOptimization::kHolderFound: {
3578       result.holder = JSObjectRef(broker(), holder);
3579       fti_data->known_receivers().insert({receiver_map.data(), result});
3580       break;
3581     }
3582     default: {
3583       DCHECK_EQ(result.holder, base::nullopt);
3584       fti_data->known_receivers().insert({receiver_map.data(), result});
3585     }
3586   }
3587   return result;
3588 }
3589 
BIMODAL_ACCESSOR(CallHandlerInfo,Object,data)3590 BIMODAL_ACCESSOR(CallHandlerInfo, Object, data)
3591 
3592 BIMODAL_ACCESSOR_C(ScopeInfo, int, ContextLength)
3593 BIMODAL_ACCESSOR_C(ScopeInfo, bool, HasContextExtensionSlot)
3594 BIMODAL_ACCESSOR_C(ScopeInfo, bool, HasOuterScopeInfo)
3595 BIMODAL_ACCESSOR(ScopeInfo, ScopeInfo, OuterScopeInfo)
3596 
3597 BIMODAL_ACCESSOR_C(SharedFunctionInfo, int, builtin_id)
3598 BIMODAL_ACCESSOR(SharedFunctionInfo, BytecodeArray, GetBytecodeArray)
3599 #define DEF_SFI_ACCESSOR(type, name) \
3600   BIMODAL_ACCESSOR_WITH_FLAG_C(SharedFunctionInfo, type, name)
3601 BROKER_SFI_FIELDS(DEF_SFI_ACCESSOR)
3602 #undef DEF_SFI_ACCESSOR
3603 BIMODAL_ACCESSOR_C(SharedFunctionInfo, SharedFunctionInfo::Inlineability,
3604                    GetInlineability)
3605 
3606 BIMODAL_ACCESSOR_C(String, int, length)
3607 
3608 BIMODAL_ACCESSOR(FeedbackCell, HeapObject, value)
3609 
3610 base::Optional<ObjectRef> MapRef::GetStrongValue(
3611     InternalIndex descriptor_index) const {
3612   if (data_->should_access_heap()) {
3613     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3614                                                             broker()->mode());
3615     MaybeObject value =
3616         object()->instance_descriptors(kRelaxedLoad).GetValue(descriptor_index);
3617     HeapObject object;
3618     if (value.GetHeapObjectIfStrong(&object)) {
3619       return ObjectRef(broker(), broker()->CanonicalPersistentHandle((object)));
3620     }
3621     return base::nullopt;
3622   }
3623   ObjectData* value = data()->AsMap()->GetStrongValue(descriptor_index);
3624   if (!value) {
3625     return base::nullopt;
3626   }
3627   return ObjectRef(broker(), value);
3628 }
3629 
SerializeRootMap()3630 void MapRef::SerializeRootMap() {
3631   if (data_->should_access_heap()) return;
3632   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
3633   data()->AsMap()->SerializeRootMap(broker());
3634 }
3635 
FindRootMap() const3636 base::Optional<MapRef> MapRef::FindRootMap() const {
3637   if (data_->should_access_heap()) {
3638     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3639                                                             broker()->mode());
3640     return MapRef(broker(), broker()->CanonicalPersistentHandle(
3641                                 object()->FindRootMap(broker()->isolate())));
3642   }
3643   ObjectData* map_data = data()->AsMap()->FindRootMap();
3644   if (map_data != nullptr) {
3645     return MapRef(broker(), map_data);
3646   }
3647   TRACE_BROKER_MISSING(broker(), "root map for object " << *this);
3648   return base::nullopt;
3649 }
3650 
data_ptr() const3651 void* JSTypedArrayRef::data_ptr() const {
3652   if (data_->should_access_heap()) {
3653     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3654                                                             broker()->mode());
3655     return object()->DataPtr();
3656   }
3657   return data()->AsJSTypedArray()->data_ptr();
3658 }
3659 
IsInobjectSlackTrackingInProgress() const3660 bool MapRef::IsInobjectSlackTrackingInProgress() const {
3661   IF_ACCESS_FROM_HEAP_C(IsInobjectSlackTrackingInProgress);
3662   return Map::Bits3::ConstructionCounterBits::decode(
3663              data()->AsMap()->bit_field3()) != Map::kNoSlackTracking;
3664 }
3665 
constructor_function_index() const3666 int MapRef::constructor_function_index() const {
3667   IF_ACCESS_FROM_HEAP_C(GetConstructorFunctionIndex);
3668   CHECK(IsPrimitiveMap());
3669   return data()->AsMap()->constructor_function_index();
3670 }
3671 
is_stable() const3672 bool MapRef::is_stable() const {
3673   IF_ACCESS_FROM_HEAP_C(is_stable);
3674   return !Map::Bits3::IsUnstableBit::decode(data()->AsMap()->bit_field3());
3675 }
3676 
CanBeDeprecated() const3677 bool MapRef::CanBeDeprecated() const {
3678   IF_ACCESS_FROM_HEAP_C(CanBeDeprecated);
3679   CHECK_GT(NumberOfOwnDescriptors(), 0);
3680   return data()->AsMap()->can_be_deprecated();
3681 }
3682 
CanTransition() const3683 bool MapRef::CanTransition() const {
3684   IF_ACCESS_FROM_HEAP_C(CanTransition);
3685   return data()->AsMap()->can_transition();
3686 }
3687 
GetInObjectPropertiesStartInWords() const3688 int MapRef::GetInObjectPropertiesStartInWords() const {
3689   IF_ACCESS_FROM_HEAP_C(GetInObjectPropertiesStartInWords);
3690   return data()->AsMap()->in_object_properties_start_in_words();
3691 }
3692 
GetInObjectProperties() const3693 int MapRef::GetInObjectProperties() const {
3694   IF_ACCESS_FROM_HEAP_C(GetInObjectProperties);
3695   return data()->AsMap()->in_object_properties();
3696 }
3697 
SerializeScopeInfoChain()3698 void ScopeInfoRef::SerializeScopeInfoChain() {
3699   if (data_->should_access_heap()) return;
3700   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
3701   data()->AsScopeInfo()->SerializeScopeInfoChain(broker());
3702 }
3703 
IsExternalString() const3704 bool StringRef::IsExternalString() const {
3705   IF_ACCESS_FROM_HEAP_C(IsExternalString);
3706   return data()->AsString()->is_external_string();
3707 }
3708 
callback() const3709 Address CallHandlerInfoRef::callback() const {
3710   if (data_->should_access_heap()) {
3711     return v8::ToCData<Address>(object()->callback());
3712   }
3713   return HeapObjectRef::data()->AsCallHandlerInfo()->callback();
3714 }
3715 
c_function() const3716 Address FunctionTemplateInfoRef::c_function() const {
3717   if (data_->should_access_heap()) {
3718     return v8::ToCData<Address>(object()->GetCFunction());
3719   }
3720   return HeapObjectRef::data()->AsFunctionTemplateInfo()->c_function();
3721 }
3722 
c_signature() const3723 const CFunctionInfo* FunctionTemplateInfoRef::c_signature() const {
3724   if (data_->should_access_heap()) {
3725     return v8::ToCData<CFunctionInfo*>(object()->GetCSignature());
3726   }
3727   return HeapObjectRef::data()->AsFunctionTemplateInfo()->c_signature();
3728 }
3729 
IsSeqString() const3730 bool StringRef::IsSeqString() const {
3731   IF_ACCESS_FROM_HEAP_C(IsSeqString);
3732   return data()->AsString()->is_seq_string();
3733 }
3734 
scope_info() const3735 ScopeInfoRef NativeContextRef::scope_info() const {
3736   if (data_->should_access_heap()) {
3737     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3738                                                           broker()->mode());
3739     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3740                                                             broker()->mode());
3741     return ScopeInfoRef(
3742         broker(), broker()->CanonicalPersistentHandle(object()->scope_info()));
3743   }
3744   return ScopeInfoRef(broker(), data()->AsNativeContext()->scope_info());
3745 }
3746 
shared_function_info() const3747 SharedFunctionInfoRef FeedbackVectorRef::shared_function_info() const {
3748   if (data_->should_access_heap()) {
3749     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3750                                                           broker()->mode());
3751     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3752                                                             broker()->mode());
3753     return SharedFunctionInfoRef(
3754         broker(),
3755         broker()->CanonicalPersistentHandle(object()->shared_function_info()));
3756   }
3757 
3758   return SharedFunctionInfoRef(
3759       broker(), data()->AsFeedbackVector()->shared_function_info());
3760 }
3761 
GetFunctionMapFromIndex(int index) const3762 MapRef NativeContextRef::GetFunctionMapFromIndex(int index) const {
3763   DCHECK_GE(index, Context::FIRST_FUNCTION_MAP_INDEX);
3764   DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX);
3765   if (data_->should_access_heap()) {
3766     return get(index).value().AsMap();
3767   }
3768   return MapRef(broker(), data()->AsNativeContext()->function_maps().at(
3769                               index - Context::FIRST_FUNCTION_MAP_INDEX));
3770 }
3771 
GetInitialJSArrayMap(ElementsKind kind) const3772 MapRef NativeContextRef::GetInitialJSArrayMap(ElementsKind kind) const {
3773   switch (kind) {
3774     case PACKED_SMI_ELEMENTS:
3775       return js_array_packed_smi_elements_map();
3776     case HOLEY_SMI_ELEMENTS:
3777       return js_array_holey_smi_elements_map();
3778     case PACKED_DOUBLE_ELEMENTS:
3779       return js_array_packed_double_elements_map();
3780     case HOLEY_DOUBLE_ELEMENTS:
3781       return js_array_holey_double_elements_map();
3782     case PACKED_ELEMENTS:
3783       return js_array_packed_elements_map();
3784     case HOLEY_ELEMENTS:
3785       return js_array_holey_elements_map();
3786     default:
3787       UNREACHABLE();
3788   }
3789 }
3790 
GetConstructorFunction(const MapRef & map) const3791 base::Optional<JSFunctionRef> NativeContextRef::GetConstructorFunction(
3792     const MapRef& map) const {
3793   CHECK(map.IsPrimitiveMap());
3794   switch (map.constructor_function_index()) {
3795     case Map::kNoConstructorFunctionIndex:
3796       return base::nullopt;
3797     case Context::BIGINT_FUNCTION_INDEX:
3798       return bigint_function();
3799     case Context::BOOLEAN_FUNCTION_INDEX:
3800       return boolean_function();
3801     case Context::NUMBER_FUNCTION_INDEX:
3802       return number_function();
3803     case Context::STRING_FUNCTION_INDEX:
3804       return string_function();
3805     case Context::SYMBOL_FUNCTION_INDEX:
3806       return symbol_function();
3807     default:
3808       UNREACHABLE();
3809   }
3810 }
3811 
IsNullOrUndefined() const3812 bool ObjectRef::IsNullOrUndefined() const {
3813   if (IsSmi()) return false;
3814   OddballType type = AsHeapObject().map().oddball_type();
3815   return type == OddballType::kNull || type == OddballType::kUndefined;
3816 }
3817 
IsTheHole() const3818 bool ObjectRef::IsTheHole() const {
3819   return IsHeapObject() &&
3820          AsHeapObject().map().oddball_type() == OddballType::kHole;
3821 }
3822 
BooleanValue() const3823 bool ObjectRef::BooleanValue() const {
3824   if (data_->should_access_heap()) {
3825     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3826                                                             broker()->mode());
3827     return object()->BooleanValue(broker()->isolate());
3828   }
3829   return IsSmi() ? (AsSmi() != 0) : data()->AsHeapObject()->boolean_value();
3830 }
3831 
OddballToNumber() const3832 Maybe<double> ObjectRef::OddballToNumber() const {
3833   OddballType type = AsHeapObject().map().oddball_type();
3834 
3835   switch (type) {
3836     case OddballType::kBoolean: {
3837       ObjectRef true_ref(broker(),
3838                          broker()->isolate()->factory()->true_value());
3839       return this->equals(true_ref) ? Just(1.0) : Just(0.0);
3840       break;
3841     }
3842     case OddballType::kUndefined: {
3843       return Just(std::numeric_limits<double>::quiet_NaN());
3844       break;
3845     }
3846     case OddballType::kNull: {
3847       return Just(0.0);
3848       break;
3849     }
3850     default: {
3851       return Nothing<double>();
3852       break;
3853     }
3854   }
3855 }
3856 
GetOwnConstantElement(uint32_t index,SerializationPolicy policy) const3857 base::Optional<ObjectRef> ObjectRef::GetOwnConstantElement(
3858     uint32_t index, SerializationPolicy policy) const {
3859   if (!(IsJSObject() || IsString())) return base::nullopt;
3860   if (data_->should_access_heap()) {
3861     // TODO(solanes, neis, v8:7790, v8:11012): Re-enable this optmization for
3862     // concurrent inlining when we have the infrastructure to safely do so.
3863     if (broker()->is_concurrent_inlining() && IsString()) return base::nullopt;
3864     CHECK_EQ(data_->kind(), ObjectDataKind::kUnserializedHeapObject);
3865     return GetOwnElementFromHeap(broker(), object(), index, true);
3866   }
3867   ObjectData* element = nullptr;
3868   if (IsJSObject()) {
3869     element =
3870         data()->AsJSObject()->GetOwnConstantElement(broker(), index, policy);
3871   } else if (IsString()) {
3872     element = data()->AsString()->GetCharAsString(broker(), index, policy);
3873   }
3874   if (element == nullptr) return base::nullopt;
3875   return ObjectRef(broker(), element);
3876 }
3877 
GetOwnDataProperty(Representation field_representation,FieldIndex index,SerializationPolicy policy) const3878 base::Optional<ObjectRef> JSObjectRef::GetOwnDataProperty(
3879     Representation field_representation, FieldIndex index,
3880     SerializationPolicy policy) const {
3881   if (data_->should_access_heap()) {
3882     return GetOwnDataPropertyFromHeap(broker(),
3883                                       Handle<JSObject>::cast(object()),
3884                                       field_representation, index);
3885   }
3886   ObjectData* property = data()->AsJSObject()->GetOwnDataProperty(
3887       broker(), field_representation, index, policy);
3888   if (property == nullptr) return base::nullopt;
3889   return ObjectRef(broker(), property);
3890 }
3891 
GetOwnCowElement(uint32_t index,SerializationPolicy policy) const3892 base::Optional<ObjectRef> JSArrayRef::GetOwnCowElement(
3893     uint32_t index, SerializationPolicy policy) const {
3894   if (data_->should_access_heap()) {
3895     if (!object()->elements().IsCowArray()) return base::nullopt;
3896     return GetOwnElementFromHeap(broker(), object(), index, false);
3897   }
3898 
3899   if (policy == SerializationPolicy::kSerializeIfNeeded) {
3900     data()->AsJSObject()->SerializeElements(broker());
3901   } else if (!data()->AsJSObject()->serialized_elements()) {
3902     TRACE(broker(), "'elements' on " << this);
3903     return base::nullopt;
3904   }
3905   if (!elements().map().IsFixedCowArrayMap()) return base::nullopt;
3906 
3907   ObjectData* element =
3908       data()->AsJSArray()->GetOwnElement(broker(), index, policy);
3909   if (element == nullptr) return base::nullopt;
3910   return ObjectRef(broker(), element);
3911 }
3912 
GetCell(int cell_index) const3913 base::Optional<CellRef> SourceTextModuleRef::GetCell(int cell_index) const {
3914   if (data_->should_access_heap() || FLAG_turbo_direct_heap_access) {
3915     AllowHandleAllocationIfNeeded allow_handle_allocation(
3916         data()->kind(), broker()->mode(), FLAG_turbo_direct_heap_access);
3917     AllowHandleDereferenceIfNeeded allow_handle_dereference(
3918         data()->kind(), broker()->mode(), FLAG_turbo_direct_heap_access);
3919     return CellRef(broker(), broker()->CanonicalPersistentHandle(
3920                                  object()->GetCell(cell_index)));
3921   }
3922   ObjectData* cell =
3923       data()->AsSourceTextModule()->GetCell(broker(), cell_index);
3924   if (cell == nullptr) return base::nullopt;
3925   return CellRef(broker(), cell);
3926 }
3927 
import_meta() const3928 ObjectRef SourceTextModuleRef::import_meta() const {
3929   if (data_->should_access_heap()) {
3930     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
3931                                                           broker()->mode());
3932     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
3933                                                             broker()->mode());
3934     return ObjectRef(
3935         broker(), broker()->CanonicalPersistentHandle(object()->import_meta()));
3936   }
3937   return ObjectRef(broker(),
3938                    data()->AsSourceTextModule()->GetImportMeta(broker()));
3939 }
3940 
ObjectRef(JSHeapBroker * broker,Handle<Object> object,bool check_type)3941 ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object,
3942                      bool check_type)
3943     : broker_(broker) {
3944   switch (broker->mode()) {
3945     // We may have to create data in JSHeapBroker::kSerialized as well since we
3946     // read the data from read only heap objects directly instead of serializing
3947     // them.
3948     case JSHeapBroker::kSerialized:
3949     case JSHeapBroker::kSerializing:
3950       data_ = broker->GetOrCreateData(object);
3951       break;
3952     case JSHeapBroker::kDisabled: {
3953       RefsMap::Entry* entry = broker->refs_->LookupOrInsert(object.address());
3954       ObjectData** storage = &(entry->value);
3955       if (*storage == nullptr) {
3956         AllowHandleDereferenceIfNeeded allow_handle_dereference(
3957             kUnserializedHeapObject, broker->mode());
3958         entry->value = broker->zone()->New<ObjectData>(
3959             broker, storage, object,
3960             object->IsSmi() ? kSmi : kUnserializedHeapObject);
3961       }
3962       data_ = *storage;
3963       break;
3964     }
3965     case JSHeapBroker::kRetired:
3966       UNREACHABLE();
3967   }
3968   if (!data_) {  // TODO(mslekova): Remove once we're on the background thread.
3969     AllowHandleDereferenceIfNeeded allow_handle_dereference(data_->kind(),
3970                                                             broker->mode());
3971     object->Print();
3972   }
3973   CHECK_WITH_MSG(data_ != nullptr, "Object is not known to the heap broker");
3974 }
3975 
3976 namespace {
GetOddballType(Isolate * isolate,Map map)3977 OddballType GetOddballType(Isolate* isolate, Map map) {
3978   if (map.instance_type() != ODDBALL_TYPE) {
3979     return OddballType::kNone;
3980   }
3981   ReadOnlyRoots roots(isolate);
3982   if (map == roots.undefined_map()) {
3983     return OddballType::kUndefined;
3984   }
3985   if (map == roots.null_map()) {
3986     return OddballType::kNull;
3987   }
3988   if (map == roots.boolean_map()) {
3989     return OddballType::kBoolean;
3990   }
3991   if (map == roots.the_hole_map()) {
3992     return OddballType::kHole;
3993   }
3994   if (map == roots.uninitialized_map()) {
3995     return OddballType::kUninitialized;
3996   }
3997   DCHECK(map == roots.termination_exception_map() ||
3998          map == roots.arguments_marker_map() ||
3999          map == roots.optimized_out_map() || map == roots.stale_register_map());
4000   return OddballType::kOther;
4001 }
4002 }  // namespace
4003 
GetHeapObjectType() const4004 HeapObjectType HeapObjectRef::GetHeapObjectType() const {
4005   if (data_->should_access_heap()) {
4006     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
4007                                                             broker()->mode());
4008     Map map = Handle<HeapObject>::cast(object())->map();
4009     HeapObjectType::Flags flags(0);
4010     if (map.is_undetectable()) flags |= HeapObjectType::kUndetectable;
4011     if (map.is_callable()) flags |= HeapObjectType::kCallable;
4012     return HeapObjectType(map.instance_type(), flags,
4013                           GetOddballType(broker()->isolate(), map));
4014   }
4015   HeapObjectType::Flags flags(0);
4016   if (map().is_undetectable()) flags |= HeapObjectType::kUndetectable;
4017   if (map().is_callable()) flags |= HeapObjectType::kCallable;
4018   return HeapObjectType(map().instance_type(), flags, map().oddball_type());
4019 }
boilerplate() const4020 base::Optional<JSObjectRef> AllocationSiteRef::boilerplate() const {
4021   if (data_->should_access_heap()) {
4022     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
4023                                                           broker()->mode());
4024     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
4025                                                             broker()->mode());
4026     return JSObjectRef(
4027         broker(), broker()->CanonicalPersistentHandle(object()->boilerplate()));
4028   }
4029   ObjectData* boilerplate = data()->AsAllocationSite()->boilerplate();
4030   if (boilerplate) {
4031     return JSObjectRef(broker(), boilerplate);
4032   } else {
4033     return base::nullopt;
4034   }
4035 }
4036 
GetElementsKind() const4037 ElementsKind JSObjectRef::GetElementsKind() const {
4038   return map().elements_kind();
4039 }
4040 
elements() const4041 FixedArrayBaseRef JSObjectRef::elements() const {
4042   if (data_->should_access_heap()) {
4043     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
4044                                                           broker()->mode());
4045     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
4046                                                             broker()->mode());
4047     return FixedArrayBaseRef(
4048         broker(), broker()->CanonicalPersistentHandle(object()->elements()));
4049   }
4050   return FixedArrayBaseRef(broker(), data()->AsJSObject()->elements());
4051 }
4052 
length() const4053 int FixedArrayBaseRef::length() const {
4054   IF_ACCESS_FROM_HEAP_C(length);
4055   return data()->AsFixedArrayBase()->length();
4056 }
4057 
Get(int i) const4058 ObjectData* FixedArrayData::Get(int i) const {
4059   CHECK_LT(i, static_cast<int>(contents_.size()));
4060   CHECK_NOT_NULL(contents_[i]);
4061   return contents_[i];
4062 }
4063 
Get(int i) const4064 Float64 FixedDoubleArrayData::Get(int i) const {
4065   CHECK_LT(i, static_cast<int>(contents_.size()));
4066   return contents_[i];
4067 }
4068 
shared_function_info() const4069 base::Optional<SharedFunctionInfoRef> FeedbackCellRef::shared_function_info()
4070     const {
4071   if (value().IsFeedbackVector()) {
4072     FeedbackVectorRef vector = value().AsFeedbackVector();
4073     if (vector.serialized()) {
4074       return value().AsFeedbackVector().shared_function_info();
4075     }
4076   }
4077   return base::nullopt;
4078 }
4079 
Serialize()4080 void FeedbackVectorRef::Serialize() {
4081   if (data_->should_access_heap()) return;
4082   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4083   data()->AsFeedbackVector()->Serialize(broker());
4084 }
4085 
serialized() const4086 bool FeedbackVectorRef::serialized() const {
4087   if (data_->should_access_heap()) return true;
4088   return data()->AsFeedbackVector()->serialized();
4089 }
4090 
IsUniqueName() const4091 bool NameRef::IsUniqueName() const {
4092   // Must match Name::IsUniqueName.
4093   return IsInternalizedString() || IsSymbol();
4094 }
4095 
data() const4096 ObjectRef JSRegExpRef::data() const {
4097   IF_ACCESS_FROM_HEAP(Object, data);
4098   return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->data());
4099 }
4100 
flags() const4101 ObjectRef JSRegExpRef::flags() const {
4102   IF_ACCESS_FROM_HEAP(Object, flags);
4103   return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->flags());
4104 }
4105 
last_index() const4106 ObjectRef JSRegExpRef::last_index() const {
4107   IF_ACCESS_FROM_HEAP(Object, last_index);
4108   return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->last_index());
4109 }
4110 
raw_properties_or_hash() const4111 ObjectRef JSRegExpRef::raw_properties_or_hash() const {
4112   IF_ACCESS_FROM_HEAP(Object, raw_properties_or_hash);
4113   return ObjectRef(broker(),
4114                    ObjectRef::data()->AsJSRegExp()->raw_properties_or_hash());
4115 }
4116 
source() const4117 ObjectRef JSRegExpRef::source() const {
4118   IF_ACCESS_FROM_HEAP(Object, source);
4119   return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->source());
4120 }
4121 
SerializeAsRegExpBoilerplate()4122 void JSRegExpRef::SerializeAsRegExpBoilerplate() {
4123   if (data_->should_access_heap()) return;
4124   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4125   JSObjectRef::data()->AsJSRegExp()->SerializeAsRegExpBoilerplate(broker());
4126 }
4127 
object() const4128 Handle<Object> ObjectRef::object() const {
4129 #ifdef DEBUG
4130   if (broker()->mode() == JSHeapBroker::kSerialized &&
4131       data_->used_status == ObjectData::Usage::kUnused) {
4132     data_->used_status = ObjectData::Usage::kOnlyIdentityUsed;
4133   }
4134 #endif  // DEBUG
4135   return data_->object();
4136 }
4137 
4138 #ifdef DEBUG
4139 #define DEF_OBJECT_GETTER(T)                                                 \
4140   Handle<T> T##Ref::object() const {                                         \
4141     if (broker()->mode() == JSHeapBroker::kSerialized &&                     \
4142         data_->used_status == ObjectData::Usage::kUnused) {                  \
4143       data_->used_status = ObjectData::Usage::kOnlyIdentityUsed;             \
4144     }                                                                        \
4145     return Handle<T>(reinterpret_cast<Address*>(data_->object().address())); \
4146   }
4147 #else
4148 #define DEF_OBJECT_GETTER(T)                                                 \
4149   Handle<T> T##Ref::object() const {                                         \
4150     return Handle<T>(reinterpret_cast<Address*>(data_->object().address())); \
4151   }
4152 #endif  // DEBUG
4153 
4154 HEAP_BROKER_SERIALIZED_OBJECT_LIST(DEF_OBJECT_GETTER)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DEF_OBJECT_GETTER)4155 HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DEF_OBJECT_GETTER)
4156 #undef DEF_OBJECT_GETTER
4157 
4158 JSHeapBroker* ObjectRef::broker() const { return broker_; }
4159 
data() const4160 ObjectData* ObjectRef::data() const {
4161   switch (broker()->mode()) {
4162     case JSHeapBroker::kDisabled:
4163       CHECK_NE(data_->kind(), kSerializedHeapObject);
4164       return data_;
4165     case JSHeapBroker::kSerializing:
4166       CHECK_NE(data_->kind(), kUnserializedHeapObject);
4167       return data_;
4168     case JSHeapBroker::kSerialized:
4169 #ifdef DEBUG
4170       data_->used_status = ObjectData::Usage::kDataUsed;
4171 #endif  // DEBUG
4172       CHECK_NE(data_->kind(), kUnserializedHeapObject);
4173       return data_;
4174     case JSHeapBroker::kRetired:
4175       UNREACHABLE();
4176   }
4177 }
4178 
NoChangeBecauseOfMissingData(JSHeapBroker * broker,const char * function,int line)4179 Reduction NoChangeBecauseOfMissingData(JSHeapBroker* broker,
4180                                        const char* function, int line) {
4181   TRACE_MISSING(broker, "data in function " << function << " at line " << line);
4182   return AdvancedReducer::NoChange();
4183 }
4184 
NativeContextData(JSHeapBroker * broker,ObjectData ** storage,Handle<NativeContext> object)4185 NativeContextData::NativeContextData(JSHeapBroker* broker, ObjectData** storage,
4186                                      Handle<NativeContext> object)
4187     : ContextData(broker, storage, object), function_maps_(broker->zone()) {}
4188 
Serialize(JSHeapBroker * broker)4189 void NativeContextData::Serialize(JSHeapBroker* broker) {
4190   if (serialized_) return;
4191   serialized_ = true;
4192 
4193   TraceScope tracer(broker, this, "NativeContextData::Serialize");
4194   Handle<NativeContext> context = Handle<NativeContext>::cast(object());
4195 
4196 #define SERIALIZE_MEMBER(type, name)                                          \
4197   DCHECK_NULL(name##_);                                                       \
4198   name##_ = broker->GetOrCreateData(context->name());                         \
4199   if (!name##_->should_access_heap()) {                                       \
4200     if (name##_->IsJSFunction()) name##_->AsJSFunction()->Serialize(broker);  \
4201     if (name##_->IsMap() &&                                                   \
4202         !InstanceTypeChecker::IsContext(name##_->AsMap()->instance_type())) { \
4203       name##_->AsMap()->SerializeConstructor(broker);                         \
4204     }                                                                         \
4205   }
4206   BROKER_COMPULSORY_NATIVE_CONTEXT_FIELDS(SERIALIZE_MEMBER)
4207   if (!broker->isolate()->bootstrapper()->IsActive()) {
4208     BROKER_OPTIONAL_NATIVE_CONTEXT_FIELDS(SERIALIZE_MEMBER)
4209   }
4210 #undef SERIALIZE_MEMBER
4211 
4212   if (!bound_function_with_constructor_map_->should_access_heap()) {
4213     bound_function_with_constructor_map_->AsMap()->SerializePrototype(broker);
4214   }
4215   if (!bound_function_without_constructor_map_->should_access_heap()) {
4216     bound_function_without_constructor_map_->AsMap()->SerializePrototype(
4217         broker);
4218   }
4219 
4220   DCHECK(function_maps_.empty());
4221   int const first = Context::FIRST_FUNCTION_MAP_INDEX;
4222   int const last = Context::LAST_FUNCTION_MAP_INDEX;
4223   function_maps_.reserve(last + 1 - first);
4224   for (int i = first; i <= last; ++i) {
4225     function_maps_.push_back(broker->GetOrCreateData(context->get(i)));
4226   }
4227 
4228   scope_info_ = broker->GetOrCreateData(context->scope_info());
4229 }
4230 
Serialize()4231 void JSFunctionRef::Serialize() {
4232   if (data_->should_access_heap()) return;
4233   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4234   data()->AsJSFunction()->Serialize(broker());
4235 }
4236 
serialized() const4237 bool JSBoundFunctionRef::serialized() const {
4238   if (data_->should_access_heap()) return true;
4239   return data()->AsJSBoundFunction()->serialized();
4240 }
4241 
serialized() const4242 bool JSFunctionRef::serialized() const {
4243   if (data_->should_access_heap()) return true;
4244   return data()->AsJSFunction()->serialized();
4245 }
4246 
GetTemplateObject(TemplateObjectDescriptionRef description,FeedbackSource const & source,SerializationPolicy policy)4247 JSArrayRef SharedFunctionInfoRef::GetTemplateObject(
4248     TemplateObjectDescriptionRef description, FeedbackSource const& source,
4249     SerializationPolicy policy) {
4250   // First, see if we have processed feedback from the vector, respecting
4251   // the serialization policy.
4252   ProcessedFeedback const& feedback =
4253       policy == SerializationPolicy::kSerializeIfNeeded
4254           ? broker()->ProcessFeedbackForTemplateObject(source)
4255           : broker()->GetFeedbackForTemplateObject(source);
4256 
4257   if (!feedback.IsInsufficient()) {
4258     return feedback.AsTemplateObject().value();
4259   }
4260 
4261   if (data_->should_access_heap()) {
4262     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
4263                                                           broker()->mode());
4264     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
4265                                                             broker()->mode());
4266     Handle<JSArray> template_object =
4267         TemplateObjectDescription::GetTemplateObject(
4268             isolate(), broker()->target_native_context().object(),
4269             description.object(), object(), source.slot.ToInt());
4270     return JSArrayRef(broker(), template_object);
4271   }
4272 
4273   ObjectData* array =
4274       data()->AsSharedFunctionInfo()->GetTemplateObject(source.slot);
4275   if (array != nullptr) return JSArrayRef(broker(), array);
4276 
4277   CHECK_EQ(policy, SerializationPolicy::kSerializeIfNeeded);
4278   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4279 
4280   Handle<JSArray> template_object =
4281       TemplateObjectDescription::GetTemplateObject(
4282           broker()->isolate(), broker()->target_native_context().object(),
4283           description.object(), object(), source.slot.ToInt());
4284   array = broker()->GetOrCreateData(template_object);
4285   data()->AsSharedFunctionInfo()->SetTemplateObject(source.slot, array);
4286   return JSArrayRef(broker(), array);
4287 }
4288 
SerializeFunctionTemplateInfo()4289 void SharedFunctionInfoRef::SerializeFunctionTemplateInfo() {
4290   if (data_->should_access_heap()) return;
4291   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4292   data()->AsSharedFunctionInfo()->SerializeFunctionTemplateInfo(broker());
4293 }
4294 
SerializeScopeInfoChain()4295 void SharedFunctionInfoRef::SerializeScopeInfoChain() {
4296   if (data_->should_access_heap()) return;
4297   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4298   data()->AsSharedFunctionInfo()->SerializeScopeInfoChain(broker());
4299 }
4300 
4301 base::Optional<FunctionTemplateInfoRef>
function_template_info() const4302 SharedFunctionInfoRef::function_template_info() const {
4303   if (data_->should_access_heap()) {
4304     if (object()->IsApiFunction()) {
4305       return FunctionTemplateInfoRef(
4306           broker(), broker()->CanonicalPersistentHandle(
4307                         object()->function_data(kAcquireLoad)));
4308     }
4309     return base::nullopt;
4310   }
4311   ObjectData* function_template_info =
4312       data()->AsSharedFunctionInfo()->function_template_info();
4313   if (!function_template_info) return base::nullopt;
4314   return FunctionTemplateInfoRef(broker(), function_template_info);
4315 }
4316 
context_header_size() const4317 int SharedFunctionInfoRef::context_header_size() const {
4318   IF_ACCESS_FROM_HEAP_C(scope_info().ContextHeaderLength);
4319   return data()->AsSharedFunctionInfo()->context_header_size();
4320 }
4321 
scope_info() const4322 ScopeInfoRef SharedFunctionInfoRef::scope_info() const {
4323   if (data_->should_access_heap()) {
4324     AllowHandleAllocationIfNeeded allow_handle_allocation(data()->kind(),
4325                                                           broker()->mode());
4326     AllowHandleDereferenceIfNeeded allow_handle_dereference(data()->kind(),
4327                                                             broker()->mode());
4328     return ScopeInfoRef(
4329         broker(), broker()->CanonicalPersistentHandle(object()->scope_info()));
4330   }
4331   return ScopeInfoRef(broker(), data()->AsSharedFunctionInfo()->scope_info());
4332 }
4333 
SerializeObjectCreateMap()4334 void JSObjectRef::SerializeObjectCreateMap() {
4335   if (data_->should_access_heap()) return;
4336   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4337   data()->AsJSObject()->SerializeObjectCreateMap(broker());
4338 }
4339 
SerializeOwnDescriptors()4340 void MapRef::SerializeOwnDescriptors() {
4341   if (data_->should_access_heap()) return;
4342   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4343   data()->AsMap()->SerializeOwnDescriptors(broker());
4344 }
4345 
SerializeOwnDescriptor(InternalIndex descriptor_index)4346 void MapRef::SerializeOwnDescriptor(InternalIndex descriptor_index) {
4347   if (data_->should_access_heap()) return;
4348   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4349   data()->AsMap()->SerializeOwnDescriptor(broker(), descriptor_index);
4350 }
4351 
serialized_own_descriptor(InternalIndex descriptor_index) const4352 bool MapRef::serialized_own_descriptor(InternalIndex descriptor_index) const {
4353   CHECK_LT(descriptor_index.as_int(), NumberOfOwnDescriptors());
4354   if (data_->should_access_heap()) return true;
4355   DescriptorArrayData* desc_array_data =
4356       data()->AsMap()->instance_descriptors();
4357   if (!desc_array_data) return false;
4358   return desc_array_data->contents().find(descriptor_index.as_int()) !=
4359          desc_array_data->contents().end();
4360 }
4361 
SerializeBackPointer()4362 void MapRef::SerializeBackPointer() {
4363   if (data_->should_access_heap()) return;
4364   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4365   data()->AsMap()->SerializeBackPointer(broker());
4366 }
4367 
SerializePrototype()4368 void MapRef::SerializePrototype() {
4369   if (data_->should_access_heap()) return;
4370   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4371   data()->AsMap()->SerializePrototype(broker());
4372 }
4373 
serialized_prototype() const4374 bool MapRef::serialized_prototype() const {
4375   CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
4376   if (data_->should_access_heap()) return true;
4377   return data()->AsMap()->serialized_prototype();
4378 }
4379 
Serialize()4380 void SourceTextModuleRef::Serialize() {
4381   if (data_->should_access_heap()) return;
4382   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4383   data()->AsSourceTextModule()->Serialize(broker());
4384 }
4385 
Serialize()4386 void NativeContextRef::Serialize() {
4387   if (data_->should_access_heap()) return;
4388   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4389   data()->AsNativeContext()->Serialize(broker());
4390 }
4391 
Serialize()4392 void JSTypedArrayRef::Serialize() {
4393   if (data_->should_access_heap()) return;
4394   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4395   data()->AsJSTypedArray()->Serialize(broker());
4396 }
4397 
serialized() const4398 bool JSTypedArrayRef::serialized() const {
4399   CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
4400   return data()->AsJSTypedArray()->serialized();
4401 }
4402 
Serialize()4403 bool JSBoundFunctionRef::Serialize() {
4404   if (data_->should_access_heap()) return true;
4405   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4406   return data()->AsJSBoundFunction()->Serialize(broker());
4407 }
4408 
Serialize()4409 void PropertyCellRef::Serialize() {
4410   if (data_->should_access_heap()) return;
4411   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4412   data()->AsPropertyCell()->Serialize(broker());
4413 }
4414 
SerializeCallCode()4415 void FunctionTemplateInfoRef::SerializeCallCode() {
4416   if (data_->should_access_heap()) return;
4417   CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
4418   data()->AsFunctionTemplateInfo()->SerializeCallCode(broker());
4419 }
4420 
GetPropertyCell(NameRef const & name,SerializationPolicy policy) const4421 base::Optional<PropertyCellRef> JSGlobalObjectRef::GetPropertyCell(
4422     NameRef const& name, SerializationPolicy policy) const {
4423   if (data_->should_access_heap()) {
4424     return GetPropertyCellFromHeap(broker(), name.object());
4425   }
4426   ObjectData* property_cell_data = data()->AsJSGlobalObject()->GetPropertyCell(
4427       broker(), name.data(), policy);
4428   if (property_cell_data == nullptr) return base::nullopt;
4429   return PropertyCellRef(broker(), property_cell_data);
4430 }
4431 
CanInlineElementAccess(MapRef const & map)4432 bool CanInlineElementAccess(MapRef const& map) {
4433   if (!map.IsJSObjectMap()) return false;
4434   if (map.is_access_check_needed()) return false;
4435   if (map.has_indexed_interceptor()) return false;
4436   ElementsKind const elements_kind = map.elements_kind();
4437   if (IsFastElementsKind(elements_kind)) return true;
4438   if (IsTypedArrayElementsKind(elements_kind) &&
4439       elements_kind != BIGUINT64_ELEMENTS &&
4440       elements_kind != BIGINT64_ELEMENTS) {
4441     return true;
4442   }
4443   return false;
4444 }
4445 
ProcessedFeedback(Kind kind,FeedbackSlotKind slot_kind)4446 ProcessedFeedback::ProcessedFeedback(Kind kind, FeedbackSlotKind slot_kind)
4447     : kind_(kind), slot_kind_(slot_kind) {}
4448 
keyed_mode() const4449 KeyedAccessMode ElementAccessFeedback::keyed_mode() const {
4450   return keyed_mode_;
4451 }
4452 
4453 ZoneVector<ElementAccessFeedback::TransitionGroup> const&
transition_groups() const4454 ElementAccessFeedback::transition_groups() const {
4455   return transition_groups_;
4456 }
4457 
Refine(ZoneVector<Handle<Map>> const & inferred_maps,Zone * zone) const4458 ElementAccessFeedback const& ElementAccessFeedback::Refine(
4459     ZoneVector<Handle<Map>> const& inferred_maps, Zone* zone) const {
4460   ElementAccessFeedback& refined_feedback =
4461       *zone->New<ElementAccessFeedback>(zone, keyed_mode(), slot_kind());
4462   if (inferred_maps.empty()) return refined_feedback;
4463 
4464   ZoneUnorderedSet<Handle<Map>, Handle<Map>::hash, Handle<Map>::equal_to>
4465       inferred(zone);
4466   inferred.insert(inferred_maps.begin(), inferred_maps.end());
4467 
4468   for (auto const& group : transition_groups()) {
4469     DCHECK(!group.empty());
4470     TransitionGroup new_group(zone);
4471     for (size_t i = 1; i < group.size(); ++i) {
4472       Handle<Map> source = group[i];
4473       if (inferred.find(source) != inferred.end()) {
4474         new_group.push_back(source);
4475       }
4476     }
4477 
4478     Handle<Map> target = group.front();
4479     bool const keep_target =
4480         inferred.find(target) != inferred.end() || new_group.size() > 1;
4481     if (keep_target) {
4482       new_group.push_back(target);
4483       // The target must be at the front, the order of sources doesn't matter.
4484       std::swap(new_group[0], new_group[new_group.size() - 1]);
4485     }
4486 
4487     if (!new_group.empty()) {
4488       DCHECK(new_group.size() == 1 || new_group.front().equals(target));
4489       refined_feedback.transition_groups_.push_back(std::move(new_group));
4490     }
4491   }
4492   return refined_feedback;
4493 }
4494 
InsufficientFeedback(FeedbackSlotKind slot_kind)4495 InsufficientFeedback::InsufficientFeedback(FeedbackSlotKind slot_kind)
4496     : ProcessedFeedback(kInsufficient, slot_kind) {}
4497 
GlobalAccessFeedback(PropertyCellRef cell,FeedbackSlotKind slot_kind)4498 GlobalAccessFeedback::GlobalAccessFeedback(PropertyCellRef cell,
4499                                            FeedbackSlotKind slot_kind)
4500     : ProcessedFeedback(kGlobalAccess, slot_kind),
4501       cell_or_context_(cell),
4502       index_and_immutable_(0 /* doesn't matter */) {
4503   DCHECK(IsGlobalICKind(slot_kind));
4504 }
4505 
GlobalAccessFeedback(FeedbackSlotKind slot_kind)4506 GlobalAccessFeedback::GlobalAccessFeedback(FeedbackSlotKind slot_kind)
4507     : ProcessedFeedback(kGlobalAccess, slot_kind),
4508       index_and_immutable_(0 /* doesn't matter */) {
4509   DCHECK(IsGlobalICKind(slot_kind));
4510 }
4511 
GlobalAccessFeedback(ContextRef script_context,int slot_index,bool immutable,FeedbackSlotKind slot_kind)4512 GlobalAccessFeedback::GlobalAccessFeedback(ContextRef script_context,
4513                                            int slot_index, bool immutable,
4514                                            FeedbackSlotKind slot_kind)
4515     : ProcessedFeedback(kGlobalAccess, slot_kind),
4516       cell_or_context_(script_context),
4517       index_and_immutable_(FeedbackNexus::SlotIndexBits::encode(slot_index) |
4518                            FeedbackNexus::ImmutabilityBit::encode(immutable)) {
4519   DCHECK_EQ(this->slot_index(), slot_index);
4520   DCHECK_EQ(this->immutable(), immutable);
4521   DCHECK(IsGlobalICKind(slot_kind));
4522 }
4523 
IsMegamorphic() const4524 bool GlobalAccessFeedback::IsMegamorphic() const {
4525   return !cell_or_context_.has_value();
4526 }
IsPropertyCell() const4527 bool GlobalAccessFeedback::IsPropertyCell() const {
4528   return cell_or_context_.has_value() && cell_or_context_->IsPropertyCell();
4529 }
IsScriptContextSlot() const4530 bool GlobalAccessFeedback::IsScriptContextSlot() const {
4531   return cell_or_context_.has_value() && cell_or_context_->IsContext();
4532 }
property_cell() const4533 PropertyCellRef GlobalAccessFeedback::property_cell() const {
4534   CHECK(IsPropertyCell());
4535   return cell_or_context_->AsPropertyCell();
4536 }
script_context() const4537 ContextRef GlobalAccessFeedback::script_context() const {
4538   CHECK(IsScriptContextSlot());
4539   return cell_or_context_->AsContext();
4540 }
slot_index() const4541 int GlobalAccessFeedback::slot_index() const {
4542   DCHECK(IsScriptContextSlot());
4543   return FeedbackNexus::SlotIndexBits::decode(index_and_immutable_);
4544 }
immutable() const4545 bool GlobalAccessFeedback::immutable() const {
4546   DCHECK(IsScriptContextSlot());
4547   return FeedbackNexus::ImmutabilityBit::decode(index_and_immutable_);
4548 }
4549 
GetConstantHint() const4550 base::Optional<ObjectRef> GlobalAccessFeedback::GetConstantHint() const {
4551   if (IsPropertyCell()) {
4552     return property_cell().value();
4553   } else if (IsScriptContextSlot() && immutable()) {
4554     return script_context().get(slot_index());
4555   } else {
4556     return base::nullopt;
4557   }
4558 }
4559 
FromNexus(FeedbackNexus const & nexus)4560 KeyedAccessMode KeyedAccessMode::FromNexus(FeedbackNexus const& nexus) {
4561   FeedbackSlotKind kind = nexus.kind();
4562   if (IsKeyedLoadICKind(kind)) {
4563     return KeyedAccessMode(AccessMode::kLoad, nexus.GetKeyedAccessLoadMode());
4564   }
4565   if (IsKeyedHasICKind(kind)) {
4566     return KeyedAccessMode(AccessMode::kHas, nexus.GetKeyedAccessLoadMode());
4567   }
4568   if (IsKeyedStoreICKind(kind)) {
4569     return KeyedAccessMode(AccessMode::kStore, nexus.GetKeyedAccessStoreMode());
4570   }
4571   if (IsStoreInArrayLiteralICKind(kind) ||
4572       IsStoreDataPropertyInLiteralKind(kind)) {
4573     return KeyedAccessMode(AccessMode::kStoreInLiteral,
4574                            nexus.GetKeyedAccessStoreMode());
4575   }
4576   UNREACHABLE();
4577 }
4578 
access_mode() const4579 AccessMode KeyedAccessMode::access_mode() const { return access_mode_; }
4580 
IsLoad() const4581 bool KeyedAccessMode::IsLoad() const {
4582   return access_mode_ == AccessMode::kLoad || access_mode_ == AccessMode::kHas;
4583 }
IsStore() const4584 bool KeyedAccessMode::IsStore() const {
4585   return access_mode_ == AccessMode::kStore ||
4586          access_mode_ == AccessMode::kStoreInLiteral;
4587 }
4588 
load_mode() const4589 KeyedAccessLoadMode KeyedAccessMode::load_mode() const {
4590   CHECK(IsLoad());
4591   return load_store_mode_.load_mode;
4592 }
4593 
store_mode() const4594 KeyedAccessStoreMode KeyedAccessMode::store_mode() const {
4595   CHECK(IsStore());
4596   return load_store_mode_.store_mode;
4597 }
4598 
LoadStoreMode(KeyedAccessLoadMode load_mode)4599 KeyedAccessMode::LoadStoreMode::LoadStoreMode(KeyedAccessLoadMode load_mode)
4600     : load_mode(load_mode) {}
LoadStoreMode(KeyedAccessStoreMode store_mode)4601 KeyedAccessMode::LoadStoreMode::LoadStoreMode(KeyedAccessStoreMode store_mode)
4602     : store_mode(store_mode) {}
4603 
KeyedAccessMode(AccessMode access_mode,KeyedAccessLoadMode load_mode)4604 KeyedAccessMode::KeyedAccessMode(AccessMode access_mode,
4605                                  KeyedAccessLoadMode load_mode)
4606     : access_mode_(access_mode), load_store_mode_(load_mode) {
4607   CHECK(!IsStore());
4608   CHECK(IsLoad());
4609 }
KeyedAccessMode(AccessMode access_mode,KeyedAccessStoreMode store_mode)4610 KeyedAccessMode::KeyedAccessMode(AccessMode access_mode,
4611                                  KeyedAccessStoreMode store_mode)
4612     : access_mode_(access_mode), load_store_mode_(store_mode) {
4613   CHECK(!IsLoad());
4614   CHECK(IsStore());
4615 }
4616 
ElementAccessFeedback(Zone * zone,KeyedAccessMode const & keyed_mode,FeedbackSlotKind slot_kind)4617 ElementAccessFeedback::ElementAccessFeedback(Zone* zone,
4618                                              KeyedAccessMode const& keyed_mode,
4619                                              FeedbackSlotKind slot_kind)
4620     : ProcessedFeedback(kElementAccess, slot_kind),
4621       keyed_mode_(keyed_mode),
4622       transition_groups_(zone) {
4623   DCHECK(IsKeyedLoadICKind(slot_kind) || IsKeyedHasICKind(slot_kind) ||
4624          IsStoreDataPropertyInLiteralKind(slot_kind) ||
4625          IsKeyedStoreICKind(slot_kind) ||
4626          IsStoreInArrayLiteralICKind(slot_kind));
4627 }
4628 
HasOnlyStringMaps(JSHeapBroker * broker) const4629 bool ElementAccessFeedback::HasOnlyStringMaps(JSHeapBroker* broker) const {
4630   for (auto const& group : transition_groups()) {
4631     for (Handle<Map> map : group) {
4632       if (!MapRef(broker, map).IsStringMap()) return false;
4633     }
4634   }
4635   return true;
4636 }
4637 
MinimorphicLoadPropertyAccessFeedback(NameRef const & name,FeedbackSlotKind slot_kind,Handle<Object> handler,ZoneVector<Handle<Map>> const & maps,bool has_migration_target_maps)4638 MinimorphicLoadPropertyAccessFeedback::MinimorphicLoadPropertyAccessFeedback(
4639     NameRef const& name, FeedbackSlotKind slot_kind, Handle<Object> handler,
4640     ZoneVector<Handle<Map>> const& maps, bool has_migration_target_maps)
4641     : ProcessedFeedback(kMinimorphicPropertyAccess, slot_kind),
4642       name_(name),
4643       handler_(handler),
4644       maps_(maps),
4645       has_migration_target_maps_(has_migration_target_maps) {
4646   DCHECK(IsLoadICKind(slot_kind));
4647 }
4648 
NamedAccessFeedback(NameRef const & name,ZoneVector<Handle<Map>> const & maps,FeedbackSlotKind slot_kind)4649 NamedAccessFeedback::NamedAccessFeedback(NameRef const& name,
4650                                          ZoneVector<Handle<Map>> const& maps,
4651                                          FeedbackSlotKind slot_kind)
4652     : ProcessedFeedback(kNamedAccess, slot_kind), name_(name), maps_(maps) {
4653   DCHECK(IsLoadICKind(slot_kind) || IsStoreICKind(slot_kind) ||
4654          IsStoreOwnICKind(slot_kind) || IsKeyedLoadICKind(slot_kind) ||
4655          IsKeyedHasICKind(slot_kind) || IsKeyedStoreICKind(slot_kind) ||
4656          IsStoreInArrayLiteralICKind(slot_kind) ||
4657          IsStoreDataPropertyInLiteralKind(slot_kind));
4658 }
4659 
SetFeedback(FeedbackSource const & source,ProcessedFeedback const * feedback)4660 void JSHeapBroker::SetFeedback(FeedbackSource const& source,
4661                                ProcessedFeedback const* feedback) {
4662   CHECK(source.IsValid());
4663   auto insertion = feedback_.insert({source, feedback});
4664   CHECK(insertion.second);
4665 }
4666 
HasFeedback(FeedbackSource const & source) const4667 bool JSHeapBroker::HasFeedback(FeedbackSource const& source) const {
4668   DCHECK(source.IsValid());
4669   return feedback_.find(source) != feedback_.end();
4670 }
4671 
GetFeedback(FeedbackSource const & source) const4672 ProcessedFeedback const& JSHeapBroker::GetFeedback(
4673     FeedbackSource const& source) const {
4674   DCHECK(source.IsValid());
4675   auto it = feedback_.find(source);
4676   CHECK_NE(it, feedback_.end());
4677   return *it->second;
4678 }
4679 
GetFeedbackSlotKind(FeedbackSource const & source) const4680 FeedbackSlotKind JSHeapBroker::GetFeedbackSlotKind(
4681     FeedbackSource const& source) const {
4682   if (is_concurrent_inlining_) {
4683     ProcessedFeedback const& processed = GetFeedback(source);
4684     return processed.slot_kind();
4685   }
4686   FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
4687   return nexus.kind();
4688 }
4689 
FeedbackIsInsufficient(FeedbackSource const & source) const4690 bool JSHeapBroker::FeedbackIsInsufficient(FeedbackSource const& source) const {
4691   return is_concurrent_inlining_ ? GetFeedback(source).IsInsufficient()
4692                                  : FeedbackNexus(source.vector, source.slot,
4693                                                  feedback_nexus_config())
4694                                        .IsUninitialized();
4695 }
4696 
4697 namespace {
4698 // Remove unupdatable and abandoned prototype maps in-place.
FilterRelevantReceiverMaps(Isolate * isolate,MapHandles * maps)4699 void FilterRelevantReceiverMaps(Isolate* isolate, MapHandles* maps) {
4700   auto in = maps->begin();
4701   auto out = in;
4702   auto end = maps->end();
4703 
4704   for (; in != end; ++in) {
4705     Handle<Map> map = *in;
4706     if (Map::TryUpdate(isolate, map).ToHandle(&map) &&
4707         !map->is_abandoned_prototype_map()) {
4708       DCHECK(!map->is_deprecated());
4709       *out = *in;
4710       ++out;
4711     }
4712   }
4713 
4714   // Remove everything between the last valid map and the end of the vector.
4715   maps->erase(out, end);
4716 }
4717 
TryGetMinimorphicHandler(std::vector<MapAndHandler> const & maps_and_handlers,FeedbackSlotKind kind,Handle<NativeContext> native_context,bool is_turboprop)4718 MaybeObjectHandle TryGetMinimorphicHandler(
4719     std::vector<MapAndHandler> const& maps_and_handlers, FeedbackSlotKind kind,
4720     Handle<NativeContext> native_context, bool is_turboprop) {
4721   if (!is_turboprop || !FLAG_turboprop_dynamic_map_checks ||
4722       !IsLoadICKind(kind)) {
4723     return MaybeObjectHandle();
4724   }
4725 
4726   // Don't use dynamic map checks when loading properties from Array.prototype.
4727   // Using dynamic map checks prevents constant folding and hence does not
4728   // inline the array builtins. We only care about monomorphic cases here. For
4729   // polymorphic loads currently we don't inline the builtins even without
4730   // dynamic map checks.
4731   if (maps_and_handlers.size() == 1 &&
4732       *maps_and_handlers[0].first ==
4733           native_context->initial_array_prototype().map()) {
4734     return MaybeObjectHandle();
4735   }
4736 
4737   MaybeObjectHandle initial_handler;
4738   for (MapAndHandler map_and_handler : maps_and_handlers) {
4739     auto map = map_and_handler.first;
4740     MaybeObjectHandle handler = map_and_handler.second;
4741     if (handler.is_null()) return MaybeObjectHandle();
4742     DCHECK(!handler->IsCleared());
4743     // TODO(mythria): extend this to DataHandlers too
4744     if (!handler.object()->IsSmi()) return MaybeObjectHandle();
4745     if (LoadHandler::GetHandlerKind(handler.object()->ToSmi()) !=
4746         LoadHandler::Kind::kField) {
4747       return MaybeObjectHandle();
4748     }
4749     CHECK(!map->IsJSGlobalProxyMap());
4750     if (initial_handler.is_null()) {
4751       initial_handler = handler;
4752     } else if (!handler.is_identical_to(initial_handler)) {
4753       return MaybeObjectHandle();
4754     }
4755   }
4756   return initial_handler;
4757 }
4758 
HasMigrationTargets(const MapHandles & maps)4759 bool HasMigrationTargets(const MapHandles& maps) {
4760   for (Handle<Map> map : maps) {
4761     if (map->is_migration_target()) return true;
4762   }
4763   return false;
4764 }
4765 }  // namespace
4766 
CanUseFeedback(const FeedbackNexus & nexus) const4767 bool JSHeapBroker::CanUseFeedback(const FeedbackNexus& nexus) const {
4768   // TODO(jgruber,v8:8888): Currently, nci code does not use any
4769   // feedback. This restriction will be relaxed in the future.
4770   return !is_native_context_independent() && !nexus.IsUninitialized();
4771 }
4772 
NewInsufficientFeedback(FeedbackSlotKind kind) const4773 const ProcessedFeedback& JSHeapBroker::NewInsufficientFeedback(
4774     FeedbackSlotKind kind) const {
4775   return *zone()->New<InsufficientFeedback>(kind);
4776 }
4777 
ReadFeedbackForPropertyAccess(FeedbackSource const & source,AccessMode mode,base::Optional<NameRef> static_name)4778 ProcessedFeedback const& JSHeapBroker::ReadFeedbackForPropertyAccess(
4779     FeedbackSource const& source, AccessMode mode,
4780     base::Optional<NameRef> static_name) {
4781   FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
4782   FeedbackSlotKind kind = nexus.kind();
4783   if (!CanUseFeedback(nexus)) return NewInsufficientFeedback(kind);
4784 
4785   std::vector<MapAndHandler> maps_and_handlers;
4786   nexus.ExtractMapsAndFeedback(&maps_and_handlers);
4787   MapHandles maps;
4788   for (auto const& entry : maps_and_handlers) {
4789     maps.push_back(entry.first);
4790   }
4791 
4792   base::Optional<NameRef> name =
4793       static_name.has_value() ? static_name : GetNameFeedback(nexus);
4794   MaybeObjectHandle handler = TryGetMinimorphicHandler(
4795       maps_and_handlers, kind, target_native_context().object(),
4796       is_turboprop());
4797   if (!handler.is_null()) {
4798     return *zone()->New<MinimorphicLoadPropertyAccessFeedback>(
4799         *name, kind, handler.object(),
4800         ZoneVector<Handle<Map>>(maps.begin(), maps.end(), zone()),
4801         HasMigrationTargets(maps));
4802   }
4803 
4804   FilterRelevantReceiverMaps(isolate(), &maps);
4805 
4806   // If no maps were found for a non-megamorphic access, then our maps died
4807   // and we should soft-deopt.
4808   if (maps.empty() && nexus.ic_state() != MEGAMORPHIC) {
4809     return NewInsufficientFeedback(kind);
4810   }
4811 
4812   if (name.has_value()) {
4813     // We rely on this invariant in JSGenericLowering.
4814     DCHECK_IMPLIES(maps.empty(), nexus.ic_state() == MEGAMORPHIC);
4815     return *zone()->New<NamedAccessFeedback>(
4816         *name, ZoneVector<Handle<Map>>(maps.begin(), maps.end(), zone()), kind);
4817   } else if (nexus.GetKeyType() == ELEMENT && !maps.empty()) {
4818     return ProcessFeedbackMapsForElementAccess(
4819         maps, KeyedAccessMode::FromNexus(nexus), kind);
4820   } else {
4821     // No actionable feedback.
4822     DCHECK(maps.empty());
4823     DCHECK_EQ(nexus.ic_state(), MEGAMORPHIC);
4824     // TODO(neis): Using ElementAccessFeedback here is kind of an abuse.
4825     return *zone()->New<ElementAccessFeedback>(
4826         zone(), KeyedAccessMode::FromNexus(nexus), kind);
4827   }
4828 }
4829 
ReadFeedbackForGlobalAccess(FeedbackSource const & source)4830 ProcessedFeedback const& JSHeapBroker::ReadFeedbackForGlobalAccess(
4831     FeedbackSource const& source) {
4832   FeedbackNexus nexus(source.vector, source.slot);
4833   DCHECK(nexus.kind() == FeedbackSlotKind::kLoadGlobalInsideTypeof ||
4834          nexus.kind() == FeedbackSlotKind::kLoadGlobalNotInsideTypeof ||
4835          nexus.kind() == FeedbackSlotKind::kStoreGlobalSloppy ||
4836          nexus.kind() == FeedbackSlotKind::kStoreGlobalStrict);
4837   if (!CanUseFeedback(nexus)) return NewInsufficientFeedback(nexus.kind());
4838   if (nexus.ic_state() != MONOMORPHIC || nexus.GetFeedback()->IsCleared()) {
4839     return *zone()->New<GlobalAccessFeedback>(nexus.kind());
4840   }
4841 
4842   Handle<Object> feedback_value(nexus.GetFeedback()->GetHeapObjectOrSmi(),
4843                                 isolate());
4844 
4845   if (feedback_value->IsSmi()) {
4846     // The wanted name belongs to a script-scope variable and the feedback
4847     // tells us where to find its value.
4848     int number = feedback_value->Number();
4849     int const script_context_index =
4850         FeedbackNexus::ContextIndexBits::decode(number);
4851     int const context_slot_index = FeedbackNexus::SlotIndexBits::decode(number);
4852     bool const immutable = FeedbackNexus::ImmutabilityBit::decode(number);
4853     Handle<Context> context = ScriptContextTable::GetContext(
4854         isolate(), target_native_context().script_context_table().object(),
4855         script_context_index);
4856     {
4857       ObjectRef contents(this,
4858                          handle(context->get(context_slot_index), isolate()));
4859       CHECK(!contents.equals(
4860           ObjectRef(this, isolate()->factory()->the_hole_value())));
4861     }
4862     ContextRef context_ref(this, context);
4863     if (immutable) {
4864       context_ref.get(context_slot_index,
4865                       SerializationPolicy::kSerializeIfNeeded);
4866     }
4867     return *zone()->New<GlobalAccessFeedback>(context_ref, context_slot_index,
4868                                               immutable, nexus.kind());
4869   }
4870 
4871   CHECK(feedback_value->IsPropertyCell());
4872   // The wanted name belongs (or did belong) to a property on the global
4873   // object and the feedback is the cell holding its value.
4874   PropertyCellRef cell(this, Handle<PropertyCell>::cast(feedback_value));
4875   cell.Serialize();
4876   return *zone()->New<GlobalAccessFeedback>(cell, nexus.kind());
4877 }
4878 
ReadFeedbackForBinaryOperation(FeedbackSource const & source) const4879 ProcessedFeedback const& JSHeapBroker::ReadFeedbackForBinaryOperation(
4880     FeedbackSource const& source) const {
4881   FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
4882   if (!CanUseFeedback(nexus)) return NewInsufficientFeedback(nexus.kind());
4883   BinaryOperationHint hint = nexus.GetBinaryOperationFeedback();
4884   DCHECK_NE(hint, BinaryOperationHint::kNone);  // Not uninitialized.
4885   return *zone()->New<BinaryOperationFeedback>(hint, nexus.kind());
4886 }
4887 
ReadFeedbackForCompareOperation(FeedbackSource const & source) const4888 ProcessedFeedback const& JSHeapBroker::ReadFeedbackForCompareOperation(
4889     FeedbackSource const& source) const {
4890   FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
4891   if (!CanUseFeedback(nexus)) return NewInsufficientFeedback(nexus.kind());
4892   CompareOperationHint hint = nexus.GetCompareOperationFeedback();
4893   DCHECK_NE(hint, CompareOperationHint::kNone);  // Not uninitialized.
4894   return *zone()->New<CompareOperationFeedback>(hint, nexus.kind());
4895 }
4896 
ReadFeedbackForForIn(FeedbackSource const & source) const4897 ProcessedFeedback const& JSHeapBroker::ReadFeedbackForForIn(
4898     FeedbackSource const& source) const {
4899   FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
4900   if (!CanUseFeedback(nexus)) return NewInsufficientFeedback(nexus.kind());
4901   ForInHint hint = nexus.GetForInFeedback();
4902   DCHECK_NE(hint, ForInHint::kNone);  // Not uninitialized.
4903   return *zone()->New<ForInFeedback>(hint, nexus.kind());
4904 }
4905 
ReadFeedbackForInstanceOf(FeedbackSource const & source)4906 ProcessedFeedback const& JSHeapBroker::ReadFeedbackForInstanceOf(
4907     FeedbackSource const& source) {
4908   FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
4909   if (!CanUseFeedback(nexus)) return NewInsufficientFeedback(nexus.kind());
4910 
4911   base::Optional<JSObjectRef> optional_constructor;
4912   {
4913     MaybeHandle<JSObject> maybe_constructor = nexus.GetConstructorFeedback();
4914     Handle<JSObject> constructor;
4915     if (maybe_constructor.ToHandle(&constructor)) {
4916       optional_constructor = JSObjectRef(this, constructor);
4917     }
4918   }
4919   return *zone()->New<InstanceOfFeedback>(optional_constructor, nexus.kind());
4920 }
4921 
ReadFeedbackForArrayOrObjectLiteral(FeedbackSource const & source)4922 ProcessedFeedback const& JSHeapBroker::ReadFeedbackForArrayOrObjectLiteral(
4923     FeedbackSource const& source) {
4924   FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
4925   if (!CanUseFeedback(nexus)) return NewInsufficientFeedback(nexus.kind());
4926 
4927   HeapObject object;
4928   if (!nexus.GetFeedback()->GetHeapObject(&object)) {
4929     return NewInsufficientFeedback(nexus.kind());
4930   }
4931 
4932   AllocationSiteRef site(this, handle(object, isolate()));
4933   if (site.IsFastLiteral()) {
4934     site.SerializeBoilerplate();
4935   }
4936 
4937   return *zone()->New<LiteralFeedback>(site, nexus.kind());
4938 }
4939 
ReadFeedbackForRegExpLiteral(FeedbackSource const & source)4940 ProcessedFeedback const& JSHeapBroker::ReadFeedbackForRegExpLiteral(
4941     FeedbackSource const& source) {
4942   FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
4943   if (!CanUseFeedback(nexus)) return NewInsufficientFeedback(nexus.kind());
4944 
4945   HeapObject object;
4946   if (!nexus.GetFeedback()->GetHeapObject(&object)) {
4947     return NewInsufficientFeedback(nexus.kind());
4948   }
4949 
4950   JSRegExpRef regexp(this, handle(object, isolate()));
4951   regexp.SerializeAsRegExpBoilerplate();
4952   return *zone()->New<RegExpLiteralFeedback>(regexp, nexus.kind());
4953 }
4954 
ReadFeedbackForTemplateObject(FeedbackSource const & source)4955 ProcessedFeedback const& JSHeapBroker::ReadFeedbackForTemplateObject(
4956     FeedbackSource const& source) {
4957   FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
4958   if (!CanUseFeedback(nexus)) return NewInsufficientFeedback(nexus.kind());
4959 
4960   HeapObject object;
4961   if (!nexus.GetFeedback()->GetHeapObject(&object)) {
4962     return NewInsufficientFeedback(nexus.kind());
4963   }
4964 
4965   JSArrayRef array(this, handle(object, isolate()));
4966   return *zone()->New<TemplateObjectFeedback>(array, nexus.kind());
4967 }
4968 
ReadFeedbackForCall(FeedbackSource const & source)4969 ProcessedFeedback const& JSHeapBroker::ReadFeedbackForCall(
4970     FeedbackSource const& source) {
4971   FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
4972   if (!CanUseFeedback(nexus)) return NewInsufficientFeedback(nexus.kind());
4973 
4974   base::Optional<HeapObjectRef> target_ref;
4975   {
4976     MaybeObject maybe_target = nexus.GetFeedback();
4977     HeapObject target_object;
4978     if (maybe_target->GetHeapObject(&target_object)) {
4979       target_ref = HeapObjectRef(this, handle(target_object, isolate()));
4980     }
4981   }
4982   float frequency = nexus.ComputeCallFrequency();
4983   SpeculationMode mode = nexus.GetSpeculationMode();
4984   return *zone()->New<CallFeedback>(target_ref, frequency, mode, nexus.kind());
4985 }
4986 
GetFeedbackForBinaryOperation(FeedbackSource const & source)4987 BinaryOperationHint JSHeapBroker::GetFeedbackForBinaryOperation(
4988     FeedbackSource const& source) {
4989   ProcessedFeedback const& feedback =
4990       is_concurrent_inlining_ ? GetFeedback(source)
4991                               : ProcessFeedbackForBinaryOperation(source);
4992   return feedback.IsInsufficient() ? BinaryOperationHint::kNone
4993                                    : feedback.AsBinaryOperation().value();
4994 }
4995 
GetFeedbackForCompareOperation(FeedbackSource const & source)4996 CompareOperationHint JSHeapBroker::GetFeedbackForCompareOperation(
4997     FeedbackSource const& source) {
4998   ProcessedFeedback const& feedback =
4999       is_concurrent_inlining_ ? GetFeedback(source)
5000                               : ProcessFeedbackForCompareOperation(source);
5001   return feedback.IsInsufficient() ? CompareOperationHint::kNone
5002                                    : feedback.AsCompareOperation().value();
5003 }
5004 
GetFeedbackForForIn(FeedbackSource const & source)5005 ForInHint JSHeapBroker::GetFeedbackForForIn(FeedbackSource const& source) {
5006   ProcessedFeedback const& feedback = is_concurrent_inlining_
5007                                           ? GetFeedback(source)
5008                                           : ProcessFeedbackForForIn(source);
5009   return feedback.IsInsufficient() ? ForInHint::kNone
5010                                    : feedback.AsForIn().value();
5011 }
5012 
GetFeedbackForPropertyAccess(FeedbackSource const & source,AccessMode mode,base::Optional<NameRef> static_name)5013 ProcessedFeedback const& JSHeapBroker::GetFeedbackForPropertyAccess(
5014     FeedbackSource const& source, AccessMode mode,
5015     base::Optional<NameRef> static_name) {
5016   return is_concurrent_inlining_
5017              ? GetFeedback(source)
5018              : ProcessFeedbackForPropertyAccess(source, mode, static_name);
5019 }
5020 
GetFeedbackForInstanceOf(FeedbackSource const & source)5021 ProcessedFeedback const& JSHeapBroker::GetFeedbackForInstanceOf(
5022     FeedbackSource const& source) {
5023   return is_concurrent_inlining_ ? GetFeedback(source)
5024                                  : ProcessFeedbackForInstanceOf(source);
5025 }
5026 
GetFeedbackForCall(FeedbackSource const & source)5027 ProcessedFeedback const& JSHeapBroker::GetFeedbackForCall(
5028     FeedbackSource const& source) {
5029   return is_concurrent_inlining_ ? GetFeedback(source)
5030                                  : ProcessFeedbackForCall(source);
5031 }
5032 
GetFeedbackForGlobalAccess(FeedbackSource const & source)5033 ProcessedFeedback const& JSHeapBroker::GetFeedbackForGlobalAccess(
5034     FeedbackSource const& source) {
5035   return is_concurrent_inlining_ ? GetFeedback(source)
5036                                  : ProcessFeedbackForGlobalAccess(source);
5037 }
5038 
GetFeedbackForArrayOrObjectLiteral(FeedbackSource const & source)5039 ProcessedFeedback const& JSHeapBroker::GetFeedbackForArrayOrObjectLiteral(
5040     FeedbackSource const& source) {
5041   return is_concurrent_inlining_
5042              ? GetFeedback(source)
5043              : ProcessFeedbackForArrayOrObjectLiteral(source);
5044 }
5045 
GetFeedbackForRegExpLiteral(FeedbackSource const & source)5046 ProcessedFeedback const& JSHeapBroker::GetFeedbackForRegExpLiteral(
5047     FeedbackSource const& source) {
5048   return is_concurrent_inlining_ ? GetFeedback(source)
5049                                  : ProcessFeedbackForRegExpLiteral(source);
5050 }
5051 
GetFeedbackForTemplateObject(FeedbackSource const & source)5052 ProcessedFeedback const& JSHeapBroker::GetFeedbackForTemplateObject(
5053     FeedbackSource const& source) {
5054   return is_concurrent_inlining_ ? GetFeedback(source)
5055                                  : ProcessFeedbackForTemplateObject(source);
5056 }
5057 
ProcessFeedbackForArrayOrObjectLiteral(FeedbackSource const & source)5058 ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForArrayOrObjectLiteral(
5059     FeedbackSource const& source) {
5060   if (HasFeedback(source)) return GetFeedback(source);
5061   ProcessedFeedback const& feedback =
5062       ReadFeedbackForArrayOrObjectLiteral(source);
5063   SetFeedback(source, &feedback);
5064   return feedback;
5065 }
5066 
ProcessFeedbackForRegExpLiteral(FeedbackSource const & source)5067 ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForRegExpLiteral(
5068     FeedbackSource const& source) {
5069   if (HasFeedback(source)) return GetFeedback(source);
5070   ProcessedFeedback const& feedback = ReadFeedbackForRegExpLiteral(source);
5071   SetFeedback(source, &feedback);
5072   return feedback;
5073 }
5074 
ProcessFeedbackForTemplateObject(FeedbackSource const & source)5075 ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForTemplateObject(
5076     FeedbackSource const& source) {
5077   if (HasFeedback(source)) return GetFeedback(source);
5078   ProcessedFeedback const& feedback = ReadFeedbackForTemplateObject(source);
5079   SetFeedback(source, &feedback);
5080   return feedback;
5081 }
5082 
ProcessFeedbackForBinaryOperation(FeedbackSource const & source)5083 ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForBinaryOperation(
5084     FeedbackSource const& source) {
5085   if (HasFeedback(source)) return GetFeedback(source);
5086   ProcessedFeedback const& feedback = ReadFeedbackForBinaryOperation(source);
5087   SetFeedback(source, &feedback);
5088   return feedback;
5089 }
5090 
ProcessFeedbackForCompareOperation(FeedbackSource const & source)5091 ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForCompareOperation(
5092     FeedbackSource const& source) {
5093   if (HasFeedback(source)) return GetFeedback(source);
5094   ProcessedFeedback const& feedback = ReadFeedbackForCompareOperation(source);
5095   SetFeedback(source, &feedback);
5096   return feedback;
5097 }
5098 
ProcessFeedbackForForIn(FeedbackSource const & source)5099 ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForForIn(
5100     FeedbackSource const& source) {
5101   if (HasFeedback(source)) return GetFeedback(source);
5102   ProcessedFeedback const& feedback = ReadFeedbackForForIn(source);
5103   SetFeedback(source, &feedback);
5104   return feedback;
5105 }
5106 
ProcessFeedbackForPropertyAccess(FeedbackSource const & source,AccessMode mode,base::Optional<NameRef> static_name)5107 ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForPropertyAccess(
5108     FeedbackSource const& source, AccessMode mode,
5109     base::Optional<NameRef> static_name) {
5110   if (HasFeedback(source)) return GetFeedback(source);
5111   ProcessedFeedback const& feedback =
5112       ReadFeedbackForPropertyAccess(source, mode, static_name);
5113   SetFeedback(source, &feedback);
5114   return feedback;
5115 }
5116 
ProcessFeedbackForInstanceOf(FeedbackSource const & source)5117 ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForInstanceOf(
5118     FeedbackSource const& source) {
5119   if (HasFeedback(source)) return GetFeedback(source);
5120   ProcessedFeedback const& feedback = ReadFeedbackForInstanceOf(source);
5121   SetFeedback(source, &feedback);
5122   return feedback;
5123 }
5124 
ProcessFeedbackForCall(FeedbackSource const & source)5125 ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForCall(
5126     FeedbackSource const& source) {
5127   if (HasFeedback(source)) return GetFeedback(source);
5128   ProcessedFeedback const& feedback = ReadFeedbackForCall(source);
5129   SetFeedback(source, &feedback);
5130   return feedback;
5131 }
5132 
ProcessFeedbackForGlobalAccess(FeedbackSource const & source)5133 ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForGlobalAccess(
5134     FeedbackSource const& source) {
5135   if (HasFeedback(source)) return GetFeedback(source);
5136   ProcessedFeedback const& feedback = ReadFeedbackForGlobalAccess(source);
5137   SetFeedback(source, &feedback);
5138   return feedback;
5139 }
5140 
ProcessFeedbackMapsForElementAccess(MapHandles const & maps,KeyedAccessMode const & keyed_mode,FeedbackSlotKind slot_kind)5141 ElementAccessFeedback const& JSHeapBroker::ProcessFeedbackMapsForElementAccess(
5142     MapHandles const& maps, KeyedAccessMode const& keyed_mode,
5143     FeedbackSlotKind slot_kind) {
5144   DCHECK(!maps.empty());
5145 
5146   // Collect possible transition targets.
5147   MapHandles possible_transition_targets;
5148   possible_transition_targets.reserve(maps.size());
5149   for (Handle<Map> map : maps) {
5150     MapRef map_ref(this, map);
5151     map_ref.SerializeRootMap();
5152 
5153     if (CanInlineElementAccess(map_ref) &&
5154         IsFastElementsKind(map->elements_kind()) &&
5155         GetInitialFastElementsKind() != map->elements_kind()) {
5156       possible_transition_targets.push_back(map);
5157     }
5158   }
5159 
5160   using TransitionGroup = ElementAccessFeedback::TransitionGroup;
5161   ZoneUnorderedMap<Handle<Map>, TransitionGroup, Handle<Map>::hash,
5162                    Handle<Map>::equal_to>
5163       transition_groups(zone());
5164 
5165   // Separate the actual receiver maps and the possible transition sources.
5166   for (Handle<Map> map : maps) {
5167     // Don't generate elements kind transitions from stable maps.
5168     Map transition_target = map->is_stable()
5169                                 ? Map()
5170                                 : map->FindElementsKindTransitionedMap(
5171                                       isolate(), possible_transition_targets);
5172     if (transition_target.is_null()) {
5173       TransitionGroup group(1, map, zone());
5174       transition_groups.insert({map, group});
5175     } else {
5176       Handle<Map> target(transition_target, isolate());
5177       TransitionGroup new_group(1, target, zone());
5178       TransitionGroup& actual_group =
5179           transition_groups.insert({target, new_group}).first->second;
5180       actual_group.push_back(map);
5181     }
5182   }
5183 
5184   ElementAccessFeedback* result =
5185       zone()->New<ElementAccessFeedback>(zone(), keyed_mode, slot_kind);
5186   for (auto entry : transition_groups) {
5187     result->AddGroup(std::move(entry.second));
5188   }
5189 
5190   CHECK(!result->transition_groups().empty());
5191   return *result;
5192 }
5193 
AddGroup(TransitionGroup && group)5194 void ElementAccessFeedback::AddGroup(TransitionGroup&& group) {
5195   CHECK(!group.empty());
5196   transition_groups_.push_back(std::move(group));
5197 
5198 #ifdef ENABLE_SLOW_DCHECKS
5199   // Check that each of the group's maps occurs exactly once in the whole
5200   // feedback. This implies that "a source is not a target".
5201   for (Handle<Map> map : group) {
5202     int count = 0;
5203     for (TransitionGroup const& some_group : transition_groups()) {
5204       count += std::count_if(
5205           some_group.begin(), some_group.end(),
5206           [&](Handle<Map> some_map) { return some_map.equals(map); });
5207     }
5208     CHECK_EQ(count, 1);
5209   }
5210 #endif
5211 }
5212 
operator <<(std::ostream & os,const ObjectRef & ref)5213 std::ostream& operator<<(std::ostream& os, const ObjectRef& ref) {
5214   if (!FLAG_concurrent_recompilation) {
5215     // We cannot be in a background thread so it's safe to read the heap.
5216     AllowHandleDereference allow_handle_dereference;
5217     return os << ref.data() << " {" << ref.object() << "}";
5218   } else if (ref.data_->should_access_heap()) {
5219     AllowHandleDereferenceIfNeeded allow_handle_dereference(
5220         ref.data()->kind(), ref.broker()->mode());
5221     return os << ref.data() << " {" << ref.object() << "}";
5222   } else {
5223     return os << ref.data();
5224   }
5225 }
5226 
GetNameFeedback(FeedbackNexus const & nexus)5227 base::Optional<NameRef> JSHeapBroker::GetNameFeedback(
5228     FeedbackNexus const& nexus) {
5229   Name raw_name = nexus.GetName();
5230   if (raw_name.is_null()) return base::nullopt;
5231   return NameRef(this, handle(raw_name, isolate()));
5232 }
5233 
GetPropertyAccessInfo(MapRef map,NameRef name,AccessMode access_mode,CompilationDependencies * dependencies,SerializationPolicy policy)5234 PropertyAccessInfo JSHeapBroker::GetPropertyAccessInfo(
5235     MapRef map, NameRef name, AccessMode access_mode,
5236     CompilationDependencies* dependencies, SerializationPolicy policy) {
5237   PropertyAccessTarget target({map, name, access_mode});
5238   auto it = property_access_infos_.find(target);
5239   if (it != property_access_infos_.end()) return it->second;
5240 
5241   if (policy == SerializationPolicy::kAssumeSerialized) {
5242     TRACE_BROKER_MISSING(this, "PropertyAccessInfo for "
5243                                    << access_mode << " of property " << name
5244                                    << " on map " << map);
5245     return PropertyAccessInfo::Invalid(zone());
5246   }
5247 
5248   CHECK_NOT_NULL(dependencies);
5249   AccessInfoFactory factory(this, dependencies, zone());
5250   PropertyAccessInfo access_info = factory.ComputePropertyAccessInfo(
5251       map.object(), name.object(), access_mode);
5252   if (is_concurrent_inlining_) {
5253     CHECK_EQ(mode(), kSerializing);
5254     TRACE(this, "Storing PropertyAccessInfo for "
5255                     << access_mode << " of property " << name << " on map "
5256                     << map);
5257     property_access_infos_.insert({target, access_info});
5258   }
5259   return access_info;
5260 }
5261 
GetPropertyAccessInfo(MinimorphicLoadPropertyAccessFeedback const & feedback,FeedbackSource const & source,SerializationPolicy policy)5262 MinimorphicLoadPropertyAccessInfo JSHeapBroker::GetPropertyAccessInfo(
5263     MinimorphicLoadPropertyAccessFeedback const& feedback,
5264     FeedbackSource const& source, SerializationPolicy policy) {
5265   auto it = minimorphic_property_access_infos_.find(source);
5266   if (it != minimorphic_property_access_infos_.end()) return it->second;
5267 
5268   if (policy == SerializationPolicy::kAssumeSerialized) {
5269     TRACE_BROKER_MISSING(this, "MinimorphicLoadPropertyAccessInfo for slot "
5270                                    << source.index() << "  "
5271                                    << ObjectRef(this, source.vector));
5272     return MinimorphicLoadPropertyAccessInfo::Invalid();
5273   }
5274 
5275   AccessInfoFactory factory(this, nullptr, zone());
5276   MinimorphicLoadPropertyAccessInfo access_info =
5277       factory.ComputePropertyAccessInfo(feedback);
5278   if (is_concurrent_inlining_) {
5279     TRACE(this, "Storing MinimorphicLoadPropertyAccessInfo for "
5280                     << source.index() << "  "
5281                     << ObjectRef(this, source.vector));
5282     minimorphic_property_access_infos_.insert({source, access_info});
5283   }
5284   return access_info;
5285 }
5286 
AsBinaryOperation() const5287 BinaryOperationFeedback const& ProcessedFeedback::AsBinaryOperation() const {
5288   CHECK_EQ(kBinaryOperation, kind());
5289   return *static_cast<BinaryOperationFeedback const*>(this);
5290 }
5291 
AsCall() const5292 CallFeedback const& ProcessedFeedback::AsCall() const {
5293   CHECK_EQ(kCall, kind());
5294   return *static_cast<CallFeedback const*>(this);
5295 }
5296 
AsCompareOperation() const5297 CompareOperationFeedback const& ProcessedFeedback::AsCompareOperation() const {
5298   CHECK_EQ(kCompareOperation, kind());
5299   return *static_cast<CompareOperationFeedback const*>(this);
5300 }
5301 
AsElementAccess() const5302 ElementAccessFeedback const& ProcessedFeedback::AsElementAccess() const {
5303   CHECK_EQ(kElementAccess, kind());
5304   return *static_cast<ElementAccessFeedback const*>(this);
5305 }
5306 
AsForIn() const5307 ForInFeedback const& ProcessedFeedback::AsForIn() const {
5308   CHECK_EQ(kForIn, kind());
5309   return *static_cast<ForInFeedback const*>(this);
5310 }
5311 
AsGlobalAccess() const5312 GlobalAccessFeedback const& ProcessedFeedback::AsGlobalAccess() const {
5313   CHECK_EQ(kGlobalAccess, kind());
5314   return *static_cast<GlobalAccessFeedback const*>(this);
5315 }
5316 
AsInstanceOf() const5317 InstanceOfFeedback const& ProcessedFeedback::AsInstanceOf() const {
5318   CHECK_EQ(kInstanceOf, kind());
5319   return *static_cast<InstanceOfFeedback const*>(this);
5320 }
5321 
AsNamedAccess() const5322 NamedAccessFeedback const& ProcessedFeedback::AsNamedAccess() const {
5323   CHECK_EQ(kNamedAccess, kind());
5324   return *static_cast<NamedAccessFeedback const*>(this);
5325 }
5326 
5327 MinimorphicLoadPropertyAccessFeedback const&
AsMinimorphicPropertyAccess() const5328 ProcessedFeedback::AsMinimorphicPropertyAccess() const {
5329   CHECK_EQ(kMinimorphicPropertyAccess, kind());
5330   return *static_cast<MinimorphicLoadPropertyAccessFeedback const*>(this);
5331 }
5332 
AsLiteral() const5333 LiteralFeedback const& ProcessedFeedback::AsLiteral() const {
5334   CHECK_EQ(kLiteral, kind());
5335   return *static_cast<LiteralFeedback const*>(this);
5336 }
5337 
AsRegExpLiteral() const5338 RegExpLiteralFeedback const& ProcessedFeedback::AsRegExpLiteral() const {
5339   CHECK_EQ(kRegExpLiteral, kind());
5340   return *static_cast<RegExpLiteralFeedback const*>(this);
5341 }
5342 
AsTemplateObject() const5343 TemplateObjectFeedback const& ProcessedFeedback::AsTemplateObject() const {
5344   CHECK_EQ(kTemplateObject, kind());
5345   return *static_cast<TemplateObjectFeedback const*>(this);
5346 }
5347 
GetBytecodeAnalysis(Handle<BytecodeArray> bytecode_array,BailoutId osr_bailout_id,bool analyze_liveness,SerializationPolicy policy)5348 BytecodeAnalysis const& JSHeapBroker::GetBytecodeAnalysis(
5349     Handle<BytecodeArray> bytecode_array, BailoutId osr_bailout_id,
5350     bool analyze_liveness, SerializationPolicy policy) {
5351   ObjectData* bytecode_array_data = GetOrCreateData(bytecode_array);
5352   CHECK_NOT_NULL(bytecode_array_data);
5353 
5354   auto it = bytecode_analyses_.find(bytecode_array_data);
5355   if (it != bytecode_analyses_.end()) {
5356     // Bytecode analysis can be run for OSR or for non-OSR. In the rare case
5357     // where we optimize for OSR and consider the top-level function itself for
5358     // inlining (because of recursion), we need both the OSR and the non-OSR
5359     // analysis. Fortunately, the only difference between the two lies in
5360     // whether the OSR entry offset gets computed (from the OSR bailout id).
5361     // Hence it's okay to reuse the OSR-version when asked for the non-OSR
5362     // version, such that we need to store at most one analysis result per
5363     // bytecode array.
5364     CHECK_IMPLIES(osr_bailout_id != it->second->osr_bailout_id(),
5365                   osr_bailout_id.IsNone());
5366     CHECK_EQ(analyze_liveness, it->second->liveness_analyzed());
5367     return *it->second;
5368   }
5369 
5370   CHECK_EQ(policy, SerializationPolicy::kSerializeIfNeeded);
5371   BytecodeAnalysis* analysis = zone()->New<BytecodeAnalysis>(
5372       bytecode_array, zone(), osr_bailout_id, analyze_liveness);
5373   DCHECK_EQ(analysis->osr_bailout_id(), osr_bailout_id);
5374   bytecode_analyses_[bytecode_array_data] = analysis;
5375   return *analysis;
5376 }
5377 
StackHasOverflowed() const5378 bool JSHeapBroker::StackHasOverflowed() const {
5379   DCHECK_IMPLIES(local_isolate_ == nullptr,
5380                  ThreadId::Current() == isolate_->thread_id());
5381   return (local_isolate_ != nullptr)
5382              ? StackLimitCheck::HasOverflowed(local_isolate_)
5383              : StackLimitCheck(isolate_).HasOverflowed();
5384 }
5385 
OffHeapBytecodeArray(BytecodeArrayRef bytecode_array)5386 OffHeapBytecodeArray::OffHeapBytecodeArray(BytecodeArrayRef bytecode_array)
5387     : array_(bytecode_array) {}
5388 
length() const5389 int OffHeapBytecodeArray::length() const { return array_.length(); }
5390 
parameter_count() const5391 int OffHeapBytecodeArray::parameter_count() const {
5392   return array_.parameter_count();
5393 }
5394 
get(int index) const5395 uint8_t OffHeapBytecodeArray::get(int index) const { return array_.get(index); }
5396 
set(int index,uint8_t value)5397 void OffHeapBytecodeArray::set(int index, uint8_t value) { UNREACHABLE(); }
5398 
GetFirstBytecodeAddress() const5399 Address OffHeapBytecodeArray::GetFirstBytecodeAddress() const {
5400   return array_.GetFirstBytecodeAddress();
5401 }
5402 
GetConstantAtIndex(int index,Isolate * isolate) const5403 Handle<Object> OffHeapBytecodeArray::GetConstantAtIndex(
5404     int index, Isolate* isolate) const {
5405   return array_.GetConstantAtIndex(index);
5406 }
5407 
IsConstantAtIndexSmi(int index) const5408 bool OffHeapBytecodeArray::IsConstantAtIndexSmi(int index) const {
5409   return array_.IsConstantAtIndexSmi(index);
5410 }
5411 
GetConstantAtIndexAsSmi(int index) const5412 Smi OffHeapBytecodeArray::GetConstantAtIndexAsSmi(int index) const {
5413   return array_.GetConstantAtIndexAsSmi(index);
5414 }
5415 
5416 #undef BIMODAL_ACCESSOR
5417 #undef BIMODAL_ACCESSOR_B
5418 #undef BIMODAL_ACCESSOR_C
5419 #undef IF_ACCESS_FROM_HEAP
5420 #undef IF_ACCESS_FROM_HEAP_C
5421 #undef TRACE
5422 #undef TRACE_MISSING
5423 
5424 }  // namespace compiler
5425 }  // namespace internal
5426 }  // namespace v8
5427