• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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/heap-refs.h"
6 
7 #ifdef ENABLE_SLOW_DCHECKS
8 #include <algorithm>
9 #endif
10 
11 #include "src/api/api-inl.h"
12 #include "src/ast/modules.h"
13 #include "src/base/optional.h"
14 #include "src/base/platform/platform.h"
15 #include "src/codegen/code-factory.h"
16 #include "src/compiler/compilation-dependencies.h"
17 #include "src/compiler/js-heap-broker.h"
18 #include "src/execution/protectors-inl.h"
19 #include "src/objects/allocation-site-inl.h"
20 #include "src/objects/descriptor-array.h"
21 #include "src/objects/heap-number-inl.h"
22 #include "src/objects/js-array-buffer-inl.h"
23 #include "src/objects/literal-objects-inl.h"
24 #include "src/objects/property-cell.h"
25 #include "src/objects/template-objects-inl.h"
26 
27 namespace v8 {
28 namespace internal {
29 namespace compiler {
30 
31 #define TRACE(broker, x) TRACE_BROKER(broker, x)
32 #define TRACE_MISSING(broker, x) TRACE_BROKER_MISSING(broker, x)
33 
34 // There are several kinds of ObjectData values.
35 //
36 // kSmi: The underlying V8 object is a Smi and the data is an instance of the
37 //   base class (ObjectData), i.e. it's basically just the handle.  Because the
38 //   object is a Smi, it's safe to access the handle in order to extract the
39 //   number value, and AsSmi() does exactly that.
40 //
41 // kBackgroundSerializedHeapObject: The underlying V8 object is a HeapObject
42 //   and the data is an instance of the corresponding (most-specific) subclass,
43 //   e.g. JSFunctionData, which provides serialized information about the
44 //   object. Allows serialization from the background thread.
45 //
46 // kUnserializedHeapObject: The underlying V8 object is a HeapObject and the
47 //   data is an instance of the base class (ObjectData), i.e. it basically
48 //   carries no information other than the handle.
49 //
50 // kNeverSerializedHeapObject: The underlying V8 object is a (potentially
51 //   mutable) HeapObject and the data is an instance of ObjectData. Its handle
52 //   must be persistent so that the GC can update it at a safepoint. Via this
53 //   handle, the object can be accessed concurrently to the main thread.
54 //
55 // kUnserializedReadOnlyHeapObject: The underlying V8 object is a read-only
56 //   HeapObject and the data is an instance of ObjectData. For
57 //   ReadOnlyHeapObjects, it is OK to access heap even from off-thread, so
58 //   these objects need not be serialized.
59 enum ObjectDataKind {
60   kSmi,
61   kBackgroundSerializedHeapObject,
62   kUnserializedHeapObject,
63   kNeverSerializedHeapObject,
64   kUnserializedReadOnlyHeapObject
65 };
66 
67 namespace {
68 
IsReadOnlyHeapObjectForCompiler(PtrComprCageBase cage_base,HeapObject object)69 bool IsReadOnlyHeapObjectForCompiler(PtrComprCageBase cage_base,
70                                      HeapObject object) {
71   DisallowGarbageCollection no_gc;
72   // TODO(jgruber): Remove this compiler-specific predicate and use the plain
73   // heap predicate instead. This would involve removing the special cases for
74   // builtins.
75   return (object.IsCode(cage_base) && Code::cast(object).is_builtin()) ||
76          ReadOnlyHeap::Contains(object);
77 }
78 
79 }  // namespace
80 
81 class ObjectData : public ZoneObject {
82  public:
ObjectData(JSHeapBroker * broker,ObjectData ** storage,Handle<Object> object,ObjectDataKind kind)83   ObjectData(JSHeapBroker* broker, ObjectData** storage, Handle<Object> object,
84              ObjectDataKind kind)
85       : object_(object),
86         kind_(kind)
87 #ifdef DEBUG
88         ,
89         broker_(broker)
90 #endif  // DEBUG
91   {
92     // This assignment ensures we don't end up inserting the same object
93     // in an endless recursion.
94     *storage = this;
95 
96     TRACE(broker, "Creating data " << this << " for handle " << object.address()
97                                    << " (" << Brief(*object) << ")");
98 
99     // It is safe to access read only heap objects and builtins from a
100     // background thread. When we read fields of these objects, we may create
101     // ObjectData on the background thread even without a canonical handle
102     // scope. This is safe too since we don't create handles but just get
103     // handles from read only root table or builtins table which is what
104     // canonical scope uses as well. For all other objects we should have
105     // created ObjectData in canonical handle scope on the main thread.
106     Isolate* isolate = broker->isolate();
107     CHECK_IMPLIES(broker->mode() == JSHeapBroker::kDisabled ||
108                       broker->mode() == JSHeapBroker::kSerializing,
109                   isolate->handle_scope_data()->canonical_scope != nullptr);
110     CHECK_IMPLIES(broker->mode() == JSHeapBroker::kSerialized,
111                   kind == kUnserializedReadOnlyHeapObject || kind == kSmi ||
112                       kind == kNeverSerializedHeapObject ||
113                       kind == kBackgroundSerializedHeapObject);
114     CHECK_IMPLIES(
115         kind == kUnserializedReadOnlyHeapObject,
116         object->IsHeapObject() && IsReadOnlyHeapObjectForCompiler(
117                                       isolate, HeapObject::cast(*object)));
118   }
119 
120 #define DECLARE_IS(Name) bool Is##Name() const;
121   HEAP_BROKER_OBJECT_LIST(DECLARE_IS)
122 #undef DECLARE_IS
123 
124 #define DECLARE_AS(Name) Name##Data* As##Name();
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(DECLARE_AS)125   HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(DECLARE_AS)
126 #undef DECLARE_AS
127 
128   Handle<Object> object() const { return object_; }
kind() const129   ObjectDataKind kind() const { return kind_; }
is_smi() const130   bool is_smi() const { return kind_ == kSmi; }
should_access_heap() const131   bool should_access_heap() const {
132     return kind_ == kUnserializedHeapObject ||
133            kind_ == kNeverSerializedHeapObject ||
134            kind_ == kUnserializedReadOnlyHeapObject;
135   }
IsNull() const136   bool IsNull() const { return object_->IsNull(); }
137 
138 #ifdef DEBUG
broker() const139   JSHeapBroker* broker() const { return broker_; }
140 #endif  // DEBUG
141 
142  private:
143   Handle<Object> const object_;
144   ObjectDataKind const kind_;
145 #ifdef DEBUG
146   JSHeapBroker* const broker_;  // For DCHECKs.
147 #endif                          // DEBUG
148 };
149 
150 class HeapObjectData : public ObjectData {
151  public:
152   HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
153                  Handle<HeapObject> object, ObjectDataKind kind);
154 
155   base::Optional<bool> TryGetBooleanValue(JSHeapBroker* broker) const;
map() const156   ObjectData* map() const { return map_; }
157   InstanceType GetMapInstanceType() const;
158 
159  private:
160   base::Optional<bool> TryGetBooleanValueImpl(JSHeapBroker* broker) const;
161 
162   ObjectData* const map_;
163 };
164 
165 class PropertyCellData : public HeapObjectData {
166  public:
167   PropertyCellData(JSHeapBroker* broker, ObjectData** storage,
168                    Handle<PropertyCell> object, ObjectDataKind kind);
169 
170   bool Cache(JSHeapBroker* broker);
171 
property_details() const172   PropertyDetails property_details() const {
173     CHECK(serialized());
174     return property_details_;
175   }
176 
value() const177   ObjectData* value() const {
178     DCHECK(serialized());
179     return value_;
180   }
181 
182  private:
183   PropertyDetails property_details_ = PropertyDetails::Empty();
184   ObjectData* value_ = nullptr;
185 
serialized() const186   bool serialized() const { return value_ != nullptr; }
187 };
188 
189 namespace {
190 
GetCFunctions(FixedArray function_overloads,Zone * zone)191 ZoneVector<Address> GetCFunctions(FixedArray function_overloads, Zone* zone) {
192   const int len = function_overloads.length() /
193                   FunctionTemplateInfo::kFunctionOverloadEntrySize;
194   ZoneVector<Address> c_functions = ZoneVector<Address>(len, zone);
195   for (int i = 0; i < len; i++) {
196     c_functions[i] = v8::ToCData<Address>(function_overloads.get(
197         FunctionTemplateInfo::kFunctionOverloadEntrySize * i));
198   }
199   return c_functions;
200 }
201 
GetCSignatures(FixedArray function_overloads,Zone * zone)202 ZoneVector<const CFunctionInfo*> GetCSignatures(FixedArray function_overloads,
203                                                 Zone* zone) {
204   const int len = function_overloads.length() /
205                   FunctionTemplateInfo::kFunctionOverloadEntrySize;
206   ZoneVector<const CFunctionInfo*> c_signatures =
207       ZoneVector<const CFunctionInfo*>(len, zone);
208   for (int i = 0; i < len; i++) {
209     c_signatures[i] = v8::ToCData<const CFunctionInfo*>(function_overloads.get(
210         FunctionTemplateInfo::kFunctionOverloadEntrySize * i + 1));
211   }
212   return c_signatures;
213 }
214 
215 }  // namespace
216 
PropertyCellData(JSHeapBroker * broker,ObjectData ** storage,Handle<PropertyCell> object,ObjectDataKind kind)217 PropertyCellData::PropertyCellData(JSHeapBroker* broker, ObjectData** storage,
218                                    Handle<PropertyCell> object,
219                                    ObjectDataKind kind)
220     : HeapObjectData(broker, storage, object, kind) {}
221 
Cache(JSHeapBroker * broker)222 bool PropertyCellData::Cache(JSHeapBroker* broker) {
223   if (serialized()) return true;
224 
225   TraceScope tracer(broker, this, "PropertyCellData::Serialize");
226   auto cell = Handle<PropertyCell>::cast(object());
227 
228   // While this code runs on a background thread, the property cell might
229   // undergo state transitions via calls to PropertyCell::Transition. These
230   // transitions follow a certain protocol on which we rely here to ensure that
231   // we only report success when we can guarantee consistent data. A key
232   // property is that after transitioning from cell type A to B (A != B), there
233   // will never be a transition back to A, unless A is kConstant and the new
234   // value is the hole (i.e. the property cell was invalidated, which is a final
235   // state).
236 
237   PropertyDetails property_details = cell->property_details(kAcquireLoad);
238 
239   Handle<Object> value =
240       broker->CanonicalPersistentHandle(cell->value(kAcquireLoad));
241   if (broker->ObjectMayBeUninitialized(value)) {
242     DCHECK(!broker->IsMainThread());
243     return false;
244   }
245 
246   {
247     PropertyDetails property_details_again =
248         cell->property_details(kAcquireLoad);
249     if (property_details != property_details_again) {
250       DCHECK(!broker->IsMainThread());
251       return false;
252     }
253   }
254 
255   if (property_details.cell_type() == PropertyCellType::kInTransition) {
256     DCHECK(!broker->IsMainThread());
257     return false;
258   }
259 
260   ObjectData* value_data = broker->TryGetOrCreateData(value);
261   if (value_data == nullptr) {
262     DCHECK(!broker->IsMainThread());
263     return false;
264   }
265 
266   PropertyCell::CheckDataIsCompatible(property_details, *value);
267 
268   DCHECK(!serialized());
269   property_details_ = property_details;
270   value_ = value_data;
271   DCHECK(serialized());
272   return true;
273 }
274 
275 class JSReceiverData : public HeapObjectData {
276  public:
JSReceiverData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSReceiver> object,ObjectDataKind kind)277   JSReceiverData(JSHeapBroker* broker, ObjectData** storage,
278                  Handle<JSReceiver> object, ObjectDataKind kind)
279       : HeapObjectData(broker, storage, object, kind) {}
280 };
281 
282 class JSObjectData : public JSReceiverData {
283  public:
JSObjectData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSObject> object,ObjectDataKind kind)284   JSObjectData(JSHeapBroker* broker, ObjectData** storage,
285                Handle<JSObject> object, ObjectDataKind kind)
286       : JSReceiverData(broker, storage, object, kind) {}
287 };
288 
289 namespace {
290 
GetOwnFastDataPropertyFromHeap(JSHeapBroker * broker,JSObjectRef holder,Representation representation,FieldIndex field_index)291 base::Optional<ObjectRef> GetOwnFastDataPropertyFromHeap(
292     JSHeapBroker* broker, JSObjectRef holder, Representation representation,
293     FieldIndex field_index) {
294   base::Optional<Object> constant;
295   {
296     DisallowGarbageCollection no_gc;
297     PtrComprCageBase cage_base = broker->cage_base();
298 
299     // This check to ensure the live map is the same as the cached map to
300     // to protect us against reads outside the bounds of the heap. This could
301     // happen if the Ref was created in a prior GC epoch, and the object
302     // shrunk in size. It might end up at the edge of a heap boundary. If
303     // we see that the map is the same in this GC epoch, we are safe.
304     Map map = holder.object()->map(cage_base, kAcquireLoad);
305     if (*holder.map().object() != map) {
306       TRACE_BROKER_MISSING(broker, "Map changed for " << holder);
307       return {};
308     }
309 
310     if (field_index.is_inobject()) {
311       constant =
312           holder.object()->RawInobjectPropertyAt(cage_base, map, field_index);
313       if (!constant.has_value()) {
314         TRACE_BROKER_MISSING(
315             broker, "Constant field in " << holder << " is unsafe to read");
316         return {};
317       }
318     } else {
319       Object raw_properties_or_hash =
320           holder.object()->raw_properties_or_hash(cage_base, kRelaxedLoad);
321       // Ensure that the object is safe to inspect.
322       if (broker->ObjectMayBeUninitialized(raw_properties_or_hash)) {
323         return {};
324       }
325       if (!raw_properties_or_hash.IsPropertyArray(cage_base)) {
326         TRACE_BROKER_MISSING(
327             broker,
328             "Expected PropertyArray for backing store in " << holder << ".");
329         return {};
330       }
331       PropertyArray properties = PropertyArray::cast(raw_properties_or_hash);
332       const int array_index = field_index.outobject_array_index();
333       if (array_index < properties.length(kAcquireLoad)) {
334         constant = properties.get(array_index);
335       } else {
336         TRACE_BROKER_MISSING(
337             broker, "Backing store for " << holder << " not long enough.");
338         return {};
339       }
340     }
341 
342     // {constant} needs to pass the gc predicate before we can introspect on it.
343     if (broker->ObjectMayBeUninitialized(constant.value())) return {};
344 
345     // Ensure that {constant} matches the {representation} we expect for the
346     // field.
347     if (!constant->FitsRepresentation(representation, false)) {
348       const char* repString =
349           constant->IsSmi()
350               ? "Smi"
351               : constant->IsHeapNumber() ? "HeapNumber" : "HeapObject";
352       TRACE_BROKER_MISSING(broker, "Mismatched representation for "
353                                        << holder << ". Expected "
354                                        << representation << ", but object is a "
355                                        << repString);
356       return {};
357     }
358   }
359 
360   // Now that we can safely inspect the constant, it may need to be wrapped.
361   Handle<Object> value = broker->CanonicalPersistentHandle(constant.value());
362   Handle<Object> possibly_wrapped = Object::WrapForRead<AllocationType::kOld>(
363       broker->local_isolate_or_isolate(), value, representation);
364   return TryMakeRef(broker, *possibly_wrapped);
365 }
366 
367 // Tries to get the property at {dict_index}. If we are within bounds of the
368 // object, we are guaranteed to see valid heap words even if the data is wrong.
GetOwnDictionaryPropertyFromHeap(JSHeapBroker * broker,Handle<JSObject> receiver,InternalIndex dict_index)369 base::Optional<ObjectRef> GetOwnDictionaryPropertyFromHeap(
370     JSHeapBroker* broker, Handle<JSObject> receiver, InternalIndex dict_index) {
371   Handle<Object> constant;
372   {
373     DisallowGarbageCollection no_gc;
374     // DictionaryPropertyAt will check that we are within the bounds of the
375     // object.
376     base::Optional<Object> maybe_constant = JSObject::DictionaryPropertyAt(
377         receiver, dict_index, broker->isolate()->heap());
378     DCHECK_IMPLIES(broker->IsMainThread(), maybe_constant);
379     if (!maybe_constant) return {};
380     constant = broker->CanonicalPersistentHandle(maybe_constant.value());
381   }
382   return TryMakeRef(broker, constant);
383 }
384 
385 }  // namespace
386 
387 class JSTypedArrayData : public JSObjectData {
388  public:
JSTypedArrayData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSTypedArray> object,ObjectDataKind kind)389   JSTypedArrayData(JSHeapBroker* broker, ObjectData** storage,
390                    Handle<JSTypedArray> object, ObjectDataKind kind)
391       : JSObjectData(broker, storage, object, kind) {}
392 };
393 
394 class JSDataViewData : public JSObjectData {
395  public:
JSDataViewData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSDataView> object,ObjectDataKind kind)396   JSDataViewData(JSHeapBroker* broker, ObjectData** storage,
397                  Handle<JSDataView> object, ObjectDataKind kind)
398       : JSObjectData(broker, storage, object, kind) {}
399 };
400 
401 class JSBoundFunctionData : public JSObjectData {
402  public:
JSBoundFunctionData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSBoundFunction> object,ObjectDataKind kind)403   JSBoundFunctionData(JSHeapBroker* broker, ObjectData** storage,
404                       Handle<JSBoundFunction> object, ObjectDataKind kind)
405       : JSObjectData(broker, storage, object, kind) {}
406 };
407 
408 class JSFunctionData : public JSObjectData {
409  public:
JSFunctionData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSFunction> object,ObjectDataKind kind)410   JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
411                  Handle<JSFunction> object, ObjectDataKind kind)
412       : JSObjectData(broker, storage, object, kind) {
413     Cache(broker);
414   }
415 
416   bool IsConsistentWithHeapState(JSHeapBroker* broker) const;
417 
has_initial_map() const418   bool has_initial_map() const {
419     DCHECK(serialized_);
420     return has_initial_map_;
421   }
has_instance_prototype() const422   bool has_instance_prototype() const {
423     DCHECK(serialized_);
424     return has_instance_prototype_;
425   }
PrototypeRequiresRuntimeLookup() const426   bool PrototypeRequiresRuntimeLookup() const {
427     DCHECK(serialized_);
428     return PrototypeRequiresRuntimeLookup_;
429   }
430 
context() const431   ObjectData* context() const {
432     DCHECK(serialized_);
433     return context_;
434   }
initial_map() const435   MapData* initial_map() const {
436     DCHECK(serialized_);
437     return initial_map_;
438   }
instance_prototype() const439   ObjectData* instance_prototype() const {
440     DCHECK(serialized_);
441     return instance_prototype_;
442   }
shared() const443   ObjectData* shared() const {
444     DCHECK(serialized_);
445     return shared_;
446   }
raw_feedback_cell() const447   ObjectData* raw_feedback_cell() const {
448     DCHECK(serialized_);
449     return feedback_cell_;
450   }
initial_map_instance_size_with_min_slack() const451   int initial_map_instance_size_with_min_slack() const {
452     DCHECK(serialized_);
453     return initial_map_instance_size_with_min_slack_;
454   }
455 
456   // Track serialized fields that are actually used, in order to relax
457   // ConsistentJSFunctionView dependency validation as much as possible.
458   enum UsedField {
459     kHasFeedbackVector = 1 << 0,
460     kPrototypeOrInitialMap = 1 << 1,
461     kHasInitialMap = 1 << 2,
462     kHasInstancePrototype = 1 << 3,
463     kPrototypeRequiresRuntimeLookup = 1 << 4,
464     kInitialMap = 1 << 5,
465     kInstancePrototype = 1 << 6,
466     kFeedbackVector = 1 << 7,
467     kFeedbackCell = 1 << 8,
468     kInitialMapInstanceSizeWithMinSlack = 1 << 9,
469   };
470 
has_any_used_field() const471   bool has_any_used_field() const { return used_fields_ != 0; }
has_used_field(UsedField used_field) const472   bool has_used_field(UsedField used_field) const {
473     return (used_fields_ & used_field) != 0;
474   }
set_used_field(UsedField used_field)475   void set_used_field(UsedField used_field) { used_fields_ |= used_field; }
476 
477  private:
478   void Cache(JSHeapBroker* broker);
479 
480 #ifdef DEBUG
481   bool serialized_ = false;
482 #endif  // DEBUG
483 
484   using UsedFields = base::Flags<UsedField>;
485   UsedFields used_fields_;
486 
487   ObjectData* prototype_or_initial_map_ = nullptr;
488   bool has_initial_map_ = false;
489   bool has_instance_prototype_ = false;
490   bool PrototypeRequiresRuntimeLookup_ = false;
491 
492   ObjectData* context_ = nullptr;
493   MapData* initial_map_ = nullptr;  // Derives from prototype_or_initial_map_.
494   ObjectData* instance_prototype_ =
495       nullptr;  // Derives from prototype_or_initial_map_.
496   ObjectData* shared_ = nullptr;
497   ObjectData* feedback_cell_ = nullptr;
498   int initial_map_instance_size_with_min_slack_;  // Derives from
499                                                   // prototype_or_initial_map_.
500 };
501 
502 class BigIntData : public HeapObjectData {
503  public:
BigIntData(JSHeapBroker * broker,ObjectData ** storage,Handle<BigInt> object,ObjectDataKind kind)504   BigIntData(JSHeapBroker* broker, ObjectData** storage, Handle<BigInt> object,
505              ObjectDataKind kind)
506       : HeapObjectData(broker, storage, object, kind),
507         as_uint64_(object->AsUint64(nullptr)) {}
508 
AsUint64() const509   uint64_t AsUint64() const { return as_uint64_; }
510 
511  private:
512   const uint64_t as_uint64_;
513 };
514 
515 struct PropertyDescriptor {
516   FieldIndex field_index;
517   ObjectData* field_owner = nullptr;
518 };
519 
520 class MapData : public HeapObjectData {
521  public:
522   MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object,
523           ObjectDataKind kind);
524 
instance_type() const525   InstanceType instance_type() const { return instance_type_; }
instance_size() const526   int instance_size() const { return instance_size_; }
bit_field3() const527   uint32_t bit_field3() const { return bit_field3_; }
in_object_properties() const528   int in_object_properties() const {
529     CHECK(InstanceTypeChecker::IsJSObject(instance_type()));
530     return in_object_properties_;
531   }
UnusedPropertyFields() const532   int UnusedPropertyFields() const { return unused_property_fields_; }
is_abandoned_prototype_map() const533   bool is_abandoned_prototype_map() const {
534     return is_abandoned_prototype_map_;
535   }
536 
537  private:
538   // The following fields should be const in principle, but construction
539   // requires locking the MapUpdater lock. For this reason, it's easier to
540   // initialize these inside the constructor body, not in the initializer list.
541 
542   InstanceType instance_type_;
543   int instance_size_;
544   uint32_t bit_field3_;
545   int unused_property_fields_;
546   bool is_abandoned_prototype_map_;
547   int in_object_properties_;
548 };
549 
550 namespace {
551 
InstanceSizeWithMinSlack(JSHeapBroker * broker,MapRef map)552 int InstanceSizeWithMinSlack(JSHeapBroker* broker, MapRef map) {
553   // This operation is split into two phases (1. map collection, 2. map
554   // processing). This is to avoid having to take two locks
555   // (full_transition_array_access and map_updater_access) at once and thus
556   // having to deal with related deadlock issues.
557   ZoneVector<Handle<Map>> maps(broker->zone());
558   maps.push_back(map.object());
559 
560   {
561     DisallowGarbageCollection no_gc;
562 
563     // Has to be an initial map.
564     DCHECK(map.object()->GetBackPointer().IsUndefined(broker->isolate()));
565 
566     static constexpr bool kConcurrentAccess = true;
567     TransitionsAccessor(broker->isolate(), *map.object(), kConcurrentAccess)
568         .TraverseTransitionTree([&](Map m) {
569           maps.push_back(broker->CanonicalPersistentHandle(m));
570         });
571   }
572 
573   // The lock is needed for UnusedPropertyFields and InstanceSizeFromSlack.
574   JSHeapBroker::MapUpdaterGuardIfNeeded mumd_scope(broker);
575 
576   int slack = std::numeric_limits<int>::max();
577   for (Handle<Map> m : maps) {
578     slack = std::min(slack, m->UnusedPropertyFields());
579   }
580 
581   return map.object()->InstanceSizeFromSlack(slack);
582 }
583 
584 }  // namespace
585 
586 // IMPORTANT: Keep this sync'd with JSFunctionData::IsConsistentWithHeapState.
Cache(JSHeapBroker * broker)587 void JSFunctionData::Cache(JSHeapBroker* broker) {
588   DCHECK(!serialized_);
589 
590   TraceScope tracer(broker, this, "JSFunctionData::Cache");
591   Handle<JSFunction> function = Handle<JSFunction>::cast(object());
592 
593   // This function may run on the background thread and thus must be individual
594   // fields in a thread-safe manner. Consistency between fields is *not*
595   // guaranteed here, instead we verify it in `IsConsistentWithHeapState`,
596   // called during job finalization. Relaxed loads are thus okay: we're
597   // guaranteed to see an initialized JSFunction object, and after
598   // initialization fields remain in a valid state.
599 
600   ContextRef context =
601       MakeRefAssumeMemoryFence(broker, function->context(kRelaxedLoad));
602   context_ = context.data();
603 
604   SharedFunctionInfoRef shared =
605       MakeRefAssumeMemoryFence(broker, function->shared(kRelaxedLoad));
606   shared_ = shared.data();
607 
608   if (function->has_prototype_slot()) {
609     prototype_or_initial_map_ = broker->GetOrCreateData(
610         function->prototype_or_initial_map(kAcquireLoad), kAssumeMemoryFence);
611 
612     has_initial_map_ = prototype_or_initial_map_->IsMap();
613     if (has_initial_map_) {
614       initial_map_ = prototype_or_initial_map_->AsMap();
615 
616       MapRef initial_map_ref = TryMakeRef<Map>(broker, initial_map_).value();
617       if (initial_map_ref.IsInobjectSlackTrackingInProgress()) {
618         initial_map_instance_size_with_min_slack_ =
619             InstanceSizeWithMinSlack(broker, initial_map_ref);
620       } else {
621         initial_map_instance_size_with_min_slack_ =
622             initial_map_ref.instance_size();
623       }
624       CHECK_GT(initial_map_instance_size_with_min_slack_, 0);
625     }
626 
627     if (has_initial_map_) {
628       has_instance_prototype_ = true;
629       instance_prototype_ =
630           MakeRefAssumeMemoryFence(
631               broker, Handle<Map>::cast(initial_map_->object())->prototype())
632               .data();
633     } else if (prototype_or_initial_map_->IsHeapObject() &&
634                !Handle<HeapObject>::cast(prototype_or_initial_map_->object())
635                     ->IsTheHole()) {
636       has_instance_prototype_ = true;
637       instance_prototype_ = prototype_or_initial_map_;
638     }
639   }
640 
641   PrototypeRequiresRuntimeLookup_ = function->PrototypeRequiresRuntimeLookup();
642 
643   FeedbackCellRef feedback_cell = MakeRefAssumeMemoryFence(
644       broker, function->raw_feedback_cell(kAcquireLoad));
645   feedback_cell_ = feedback_cell.data();
646 
647 #ifdef DEBUG
648   serialized_ = true;
649 #endif  // DEBUG
650 }
651 
652 // IMPORTANT: Keep this sync'd with JSFunctionData::Cache.
IsConsistentWithHeapState(JSHeapBroker * broker) const653 bool JSFunctionData::IsConsistentWithHeapState(JSHeapBroker* broker) const {
654   DCHECK(serialized_);
655 
656   Handle<JSFunction> f = Handle<JSFunction>::cast(object());
657 
658   CHECK_EQ(*context_->object(), f->context());
659   CHECK_EQ(*shared_->object(), f->shared());
660 
661   if (f->has_prototype_slot()) {
662     if (has_used_field(kPrototypeOrInitialMap) &&
663         *prototype_or_initial_map_->object() !=
664             f->prototype_or_initial_map(kAcquireLoad)) {
665       TRACE_BROKER_MISSING(broker, "JSFunction::prototype_or_initial_map");
666       return false;
667     }
668     if (has_used_field(kHasInitialMap) &&
669         has_initial_map_ != f->has_initial_map()) {
670       TRACE_BROKER_MISSING(broker, "JSFunction::has_initial_map");
671       return false;
672     }
673     if (has_used_field(kHasInstancePrototype) &&
674         has_instance_prototype_ != f->has_instance_prototype()) {
675       TRACE_BROKER_MISSING(broker, "JSFunction::has_instance_prototype");
676       return false;
677     }
678   } else {
679     DCHECK(!has_initial_map_);
680     DCHECK(!has_instance_prototype_);
681   }
682 
683   if (has_initial_map()) {
684     if (has_used_field(kInitialMap) &&
685         *initial_map_->object() != f->initial_map()) {
686       TRACE_BROKER_MISSING(broker, "JSFunction::initial_map");
687       return false;
688     }
689     if (has_used_field(kInitialMapInstanceSizeWithMinSlack) &&
690         initial_map_instance_size_with_min_slack_ !=
691             f->ComputeInstanceSizeWithMinSlack(f->GetIsolate())) {
692       TRACE_BROKER_MISSING(broker,
693                            "JSFunction::ComputeInstanceSizeWithMinSlack");
694       return false;
695     }
696   } else {
697     DCHECK_NULL(initial_map_);
698   }
699 
700   if (has_instance_prototype_) {
701     if (has_used_field(kInstancePrototype) &&
702         *instance_prototype_->object() != f->instance_prototype()) {
703       TRACE_BROKER_MISSING(broker, "JSFunction::instance_prototype");
704       return false;
705     }
706   } else {
707     DCHECK_NULL(instance_prototype_);
708   }
709 
710   if (has_used_field(kPrototypeRequiresRuntimeLookup) &&
711       PrototypeRequiresRuntimeLookup_ != f->PrototypeRequiresRuntimeLookup()) {
712     TRACE_BROKER_MISSING(broker, "JSFunction::PrototypeRequiresRuntimeLookup");
713     return false;
714   }
715 
716   if (has_used_field(kFeedbackCell) &&
717       *feedback_cell_->object() != f->raw_feedback_cell()) {
718     TRACE_BROKER_MISSING(broker, "JSFunction::raw_feedback_cell");
719     return false;
720   }
721 
722   return true;
723 }
724 
IsConsistentWithHeapState() const725 bool JSFunctionRef::IsConsistentWithHeapState() const {
726   DCHECK(broker()->IsMainThread());
727   return data()->AsJSFunction()->IsConsistentWithHeapState(broker());
728 }
729 
HeapObjectData(JSHeapBroker * broker,ObjectData ** storage,Handle<HeapObject> object,ObjectDataKind kind)730 HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
731                                Handle<HeapObject> object, ObjectDataKind kind)
732     : ObjectData(broker, storage, object, kind),
733       map_(broker->GetOrCreateData(
734           object->map(broker->cage_base(), kAcquireLoad), kAssumeMemoryFence)) {
735   CHECK_IMPLIES(broker->mode() == JSHeapBroker::kSerialized,
736                 kind == kBackgroundSerializedHeapObject);
737 }
738 
TryGetBooleanValue(JSHeapBroker * broker) const739 base::Optional<bool> HeapObjectData::TryGetBooleanValue(
740     JSHeapBroker* broker) const {
741   // Keep in sync with Object::BooleanValue.
742   auto result = TryGetBooleanValueImpl(broker);
743   DCHECK_IMPLIES(broker->IsMainThread() && result.has_value(),
744                  result.value() == object()->BooleanValue(broker->isolate()));
745   return result;
746 }
747 
TryGetBooleanValueImpl(JSHeapBroker * broker) const748 base::Optional<bool> HeapObjectData::TryGetBooleanValueImpl(
749     JSHeapBroker* broker) const {
750   DisallowGarbageCollection no_gc;
751   Object o = *object();
752   Isolate* isolate = broker->isolate();
753   const InstanceType t = GetMapInstanceType();
754   if (o.IsTrue(isolate)) {
755     return true;
756   } else if (o.IsFalse(isolate)) {
757     return false;
758   } else if (o.IsNullOrUndefined(isolate)) {
759     return false;
760   } else if (MapRef{broker, map()}.is_undetectable()) {
761     return false;  // Undetectable object is false.
762   } else if (InstanceTypeChecker::IsString(t)) {
763     // TODO(jgruber): Implement in possible cases.
764     return {};
765   } else if (InstanceTypeChecker::IsHeapNumber(t)) {
766     return {};
767   } else if (InstanceTypeChecker::IsBigInt(t)) {
768     return {};
769   }
770   return true;
771 }
772 
GetMapInstanceType() const773 InstanceType HeapObjectData::GetMapInstanceType() const {
774   ObjectData* map_data = map();
775   if (map_data->should_access_heap()) {
776     return Handle<Map>::cast(map_data->object())->instance_type();
777   }
778   return map_data->AsMap()->instance_type();
779 }
780 
781 namespace {
782 
IsReadOnlyLengthDescriptor(Isolate * isolate,Handle<Map> jsarray_map)783 bool IsReadOnlyLengthDescriptor(Isolate* isolate, Handle<Map> jsarray_map) {
784   DCHECK(!jsarray_map->is_dictionary_map());
785   DescriptorArray descriptors =
786       jsarray_map->instance_descriptors(isolate, kRelaxedLoad);
787   static_assert(
788       JSArray::kLengthOffset == JSObject::kHeaderSize,
789       "The length should be the first property on the descriptor array");
790   InternalIndex offset(0);
791   return descriptors.GetDetails(offset).IsReadOnly();
792 }
793 
794 // Important: this predicate does not check Protectors::IsNoElementsIntact. The
795 // compiler checks protectors through the compilation dependency mechanism; it
796 // doesn't make sense to do that here as part of every MapData construction.
797 // Callers *must* take care to take the correct dependency themselves.
SupportsFastArrayIteration(JSHeapBroker * broker,Handle<Map> map)798 bool SupportsFastArrayIteration(JSHeapBroker* broker, Handle<Map> map) {
799   return map->instance_type() == JS_ARRAY_TYPE &&
800          IsFastElementsKind(map->elements_kind()) &&
801          map->prototype().IsJSArray() &&
802          broker->IsArrayOrObjectPrototype(broker->CanonicalPersistentHandle(
803              JSArray::cast(map->prototype())));
804 }
805 
SupportsFastArrayResize(JSHeapBroker * broker,Handle<Map> map)806 bool SupportsFastArrayResize(JSHeapBroker* broker, Handle<Map> map) {
807   return SupportsFastArrayIteration(broker, map) && map->is_extensible() &&
808          !map->is_dictionary_map() &&
809          !IsReadOnlyLengthDescriptor(broker->isolate(), map);
810 }
811 
812 }  // namespace
813 
MapData(JSHeapBroker * broker,ObjectData ** storage,Handle<Map> object,ObjectDataKind kind)814 MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object,
815                  ObjectDataKind kind)
816     : HeapObjectData(broker, storage, object, kind) {
817   // This lock ensure that MapData can always be background-serialized, i.e.
818   // while the lock is held the Map object may not be modified (except in
819   // benign ways).
820   // TODO(jgruber): Consider removing this lock by being smrt.
821   JSHeapBroker::MapUpdaterGuardIfNeeded mumd_scope(broker);
822 
823   // When background serializing the map, we can perform a lite serialization
824   // since the MapRef will read some of the Map's fields can be read directly.
825 
826   // Even though MapRefs can read {instance_type} directly, other classes depend
827   // on {instance_type} being serialized.
828   instance_type_ = object->instance_type();
829   instance_size_ = object->instance_size();
830 
831   // Both bit_field3 (and below bit_field) are special fields: Even though most
832   // of the individual bits inside of the bitfield could be read / written
833   // non-atomically, the bitfield itself has to use atomic relaxed accessors
834   // since some fields since can be modified in live objects.
835   // TODO(solanes, v8:7790): Assess if adding the exclusive lock in more places
836   // (e.g for set_has_non_instance_prototype) makes sense. Pros: these fields
837   // can use the non-atomic accessors. Cons: We would be acquiring an exclusive
838   // lock in more places.
839   bit_field3_ = object->relaxed_bit_field3();
840   unused_property_fields_ = object->UnusedPropertyFields();
841   is_abandoned_prototype_map_ = object->is_abandoned_prototype_map();
842   in_object_properties_ =
843       object->IsJSObjectMap() ? object->GetInObjectProperties() : 0;
844 }
845 
846 class FixedArrayBaseData : public HeapObjectData {
847  public:
FixedArrayBaseData(JSHeapBroker * broker,ObjectData ** storage,Handle<FixedArrayBase> object,ObjectDataKind kind)848   FixedArrayBaseData(JSHeapBroker* broker, ObjectData** storage,
849                      Handle<FixedArrayBase> object, ObjectDataKind kind)
850       : HeapObjectData(broker, storage, object, kind),
851         length_(object->length(kAcquireLoad)) {}
852 
length() const853   int length() const { return length_; }
854 
855  private:
856   int const length_;
857 };
858 
859 class FixedArrayData : public FixedArrayBaseData {
860  public:
FixedArrayData(JSHeapBroker * broker,ObjectData ** storage,Handle<FixedArray> object,ObjectDataKind kind)861   FixedArrayData(JSHeapBroker* broker, ObjectData** storage,
862                  Handle<FixedArray> object, ObjectDataKind kind)
863       : FixedArrayBaseData(broker, storage, object, kind) {}
864 };
865 
866 // Only used in JSNativeContextSpecialization.
867 class ScriptContextTableData : public FixedArrayData {
868  public:
ScriptContextTableData(JSHeapBroker * broker,ObjectData ** storage,Handle<ScriptContextTable> object,ObjectDataKind kind)869   ScriptContextTableData(JSHeapBroker* broker, ObjectData** storage,
870                          Handle<ScriptContextTable> object, ObjectDataKind kind)
871       : FixedArrayData(broker, storage, object, kind) {}
872 };
873 
874 class JSArrayData : public JSObjectData {
875  public:
JSArrayData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSArray> object,ObjectDataKind kind)876   JSArrayData(JSHeapBroker* broker, ObjectData** storage,
877               Handle<JSArray> object, ObjectDataKind kind)
878       : JSObjectData(broker, storage, object, kind) {}
879 };
880 
881 class JSGlobalObjectData : public JSObjectData {
882  public:
JSGlobalObjectData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSGlobalObject> object,ObjectDataKind kind)883   JSGlobalObjectData(JSHeapBroker* broker, ObjectData** storage,
884                      Handle<JSGlobalObject> object, ObjectDataKind kind)
885       : JSObjectData(broker, storage, object, kind) {}
886 };
887 
888 class JSGlobalProxyData : public JSObjectData {
889  public:
JSGlobalProxyData(JSHeapBroker * broker,ObjectData ** storage,Handle<JSGlobalProxy> object,ObjectDataKind kind)890   JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage,
891                     Handle<JSGlobalProxy> object, ObjectDataKind kind)
892       : JSObjectData(broker, storage, object, kind) {}
893 };
894 
895 #define DEFINE_IS(Name)                                                 \
896   bool ObjectData::Is##Name() const {                                   \
897     if (should_access_heap()) {                                         \
898       return object()->Is##Name();                                      \
899     }                                                                   \
900     if (is_smi()) return false;                                         \
901     InstanceType instance_type =                                        \
902         static_cast<const HeapObjectData*>(this)->GetMapInstanceType(); \
903     return InstanceTypeChecker::Is##Name(instance_type);                \
904   }
905 HEAP_BROKER_OBJECT_LIST(DEFINE_IS)
906 #undef DEFINE_IS
907 
908 #define DEFINE_AS(Name)                              \
909   Name##Data* ObjectData::As##Name() {               \
910     CHECK(Is##Name());                               \
911     CHECK(kind_ == kBackgroundSerializedHeapObject); \
912     return static_cast<Name##Data*>(this);           \
913   }
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(DEFINE_AS)914 HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(DEFINE_AS)
915 #undef DEFINE_AS
916 
917 bool ObjectRef::equals(const ObjectRef& other) const {
918   return data_ == other.data_;
919 }
920 
isolate() const921 Isolate* ObjectRef::isolate() const { return broker()->isolate(); }
922 
previous(size_t * depth) const923 ContextRef ContextRef::previous(size_t* depth) const {
924   DCHECK_NOT_NULL(depth);
925 
926   Context current = *object();
927   while (*depth != 0 && current.unchecked_previous().IsContext()) {
928     current = Context::cast(current.unchecked_previous());
929     (*depth)--;
930   }
931   // The `previous` field is immutable after initialization and the
932   // context itself is read through an atomic load.
933   return MakeRefAssumeMemoryFence(broker(), current);
934 }
935 
get(int index) const936 base::Optional<ObjectRef> ContextRef::get(int index) const {
937   CHECK_LE(0, index);
938   // Length is immutable after initialization.
939   if (index >= object()->length(kRelaxedLoad)) return {};
940   return TryMakeRef(broker(), object()->get(index));
941 }
942 
InitializeAndStartSerializing()943 void JSHeapBroker::InitializeAndStartSerializing() {
944   TraceScope tracer(this, "JSHeapBroker::InitializeAndStartSerializing");
945 
946   CHECK_EQ(mode_, kDisabled);
947   mode_ = kSerializing;
948 
949   // Throw away the dummy data that we created while disabled.
950   feedback_.clear();
951   refs_->Clear();
952   refs_ =
953       zone()->New<RefsMap>(kInitialRefsBucketCount, AddressMatcher(), zone());
954 
955   CollectArrayAndObjectPrototypes();
956 
957   SetTargetNativeContextRef(target_native_context().object());
958 }
959 
960 namespace {
961 
ObjectDataKindFor(RefSerializationKind kind)962 constexpr ObjectDataKind ObjectDataKindFor(RefSerializationKind kind) {
963   switch (kind) {
964     case RefSerializationKind::kBackgroundSerialized:
965       return kBackgroundSerializedHeapObject;
966     case RefSerializationKind::kNeverSerialized:
967       return kNeverSerializedHeapObject;
968   }
969 }
970 
971 }  // namespace
972 
TryGetOrCreateData(Handle<Object> object,GetOrCreateDataFlags flags)973 ObjectData* JSHeapBroker::TryGetOrCreateData(Handle<Object> object,
974                                              GetOrCreateDataFlags flags) {
975   RefsMap::Entry* entry = refs_->Lookup(object.address());
976   if (entry != nullptr) return entry->value;
977 
978   if (mode() == JSHeapBroker::kDisabled) {
979     entry = refs_->LookupOrInsert(object.address());
980     ObjectData** storage = &entry->value;
981     if (*storage == nullptr) {
982       entry->value = zone()->New<ObjectData>(
983           this, storage, object,
984           object->IsSmi() ? kSmi : kUnserializedHeapObject);
985     }
986     return *storage;
987   }
988 
989   CHECK(mode() == JSHeapBroker::kSerializing ||
990         mode() == JSHeapBroker::kSerialized);
991 
992   ObjectData* object_data;
993   if (object->IsSmi()) {
994     entry = refs_->LookupOrInsert(object.address());
995     return zone()->New<ObjectData>(this, &entry->value, object, kSmi);
996   }
997 
998   DCHECK(!object->IsSmi());
999 
1000   const bool crash_on_error = (flags & kCrashOnError) != 0;
1001 
1002   if ((flags & kAssumeMemoryFence) == 0 &&
1003       ObjectMayBeUninitialized(HeapObject::cast(*object))) {
1004     TRACE_BROKER_MISSING(this, "Object may be uninitialized " << *object);
1005     CHECK_WITH_MSG(!crash_on_error, "Ref construction failed");
1006     return nullptr;
1007   }
1008 
1009   if (IsReadOnlyHeapObjectForCompiler(isolate(), HeapObject::cast(*object))) {
1010     entry = refs_->LookupOrInsert(object.address());
1011     return zone()->New<ObjectData>(this, &entry->value, object,
1012                                    kUnserializedReadOnlyHeapObject);
1013   }
1014 
1015 #define CREATE_DATA(Name)                                             \
1016   if (object->Is##Name()) {                                           \
1017     entry = refs_->LookupOrInsert(object.address());                  \
1018     object_data = zone()->New<ref_traits<Name>::data_type>(           \
1019         this, &entry->value, Handle<Name>::cast(object),              \
1020         ObjectDataKindFor(ref_traits<Name>::ref_serialization_kind)); \
1021     /* NOLINTNEXTLINE(readability/braces) */                          \
1022   } else
1023   HEAP_BROKER_OBJECT_LIST(CREATE_DATA)
1024 #undef CREATE_DATA
1025   {
1026     UNREACHABLE();
1027   }
1028   // At this point the entry pointer is not guaranteed to be valid as
1029   // the refs_ hash hable could be resized by one of the constructors above.
1030   DCHECK_EQ(object_data, refs_->Lookup(object.address())->value);
1031   return object_data;
1032 }
1033 
1034 #define DEFINE_IS_AND_AS(Name)                                    \
1035   bool ObjectRef::Is##Name() const { return data()->Is##Name(); } \
1036   Name##Ref ObjectRef::As##Name() const {                         \
1037     DCHECK(Is##Name());                                           \
1038     return Name##Ref(broker(), data());                           \
1039   }
HEAP_BROKER_OBJECT_LIST(DEFINE_IS_AND_AS)1040 HEAP_BROKER_OBJECT_LIST(DEFINE_IS_AND_AS)
1041 #undef DEFINE_IS_AND_AS
1042 
1043 bool ObjectRef::IsSmi() const { return data()->is_smi(); }
1044 
AsSmi() const1045 int ObjectRef::AsSmi() const {
1046   DCHECK(IsSmi());
1047   // Handle-dereference is always allowed for Handle<Smi>.
1048   return Handle<Smi>::cast(object())->value();
1049 }
1050 
1051 #define DEF_TESTER(Type, ...)                              \
1052   bool MapRef::Is##Type##Map() const {                     \
1053     return InstanceTypeChecker::Is##Type(instance_type()); \
1054   }
INSTANCE_TYPE_CHECKERS(DEF_TESTER)1055 INSTANCE_TYPE_CHECKERS(DEF_TESTER)
1056 #undef DEF_TESTER
1057 
1058 bool MapRef::CanInlineElementAccess() const {
1059   if (!IsJSObjectMap()) return false;
1060   if (is_access_check_needed()) return false;
1061   if (has_indexed_interceptor()) return false;
1062   ElementsKind kind = elements_kind();
1063   if (IsFastElementsKind(kind)) return true;
1064   if (IsTypedArrayElementsKind(kind) && kind != BIGUINT64_ELEMENTS &&
1065       kind != BIGINT64_ELEMENTS) {
1066     return true;
1067   }
1068   return false;
1069 }
1070 
AsElementsKind(ElementsKind kind) const1071 base::Optional<MapRef> MapRef::AsElementsKind(ElementsKind kind) const {
1072   const ElementsKind current_kind = elements_kind();
1073   if (kind == current_kind) return *this;
1074 
1075   base::Optional<Map> maybe_result = Map::TryAsElementsKind(
1076       broker()->isolate(), object(), kind, ConcurrencyMode::kConcurrent);
1077 
1078 #ifdef DEBUG
1079   // If starting from an initial JSArray map, TryAsElementsKind must succeed
1080   // and return the expected transitioned JSArray map.
1081   NativeContextRef native_context = broker()->target_native_context();
1082   if (equals(native_context.GetInitialJSArrayMap(current_kind))) {
1083     CHECK_EQ(Map::TryAsElementsKind(broker()->isolate(), object(), kind,
1084                                     ConcurrencyMode::kConcurrent)
1085                  .value(),
1086              *native_context.GetInitialJSArrayMap(kind).object());
1087   }
1088 #endif  // DEBUG
1089 
1090   if (!maybe_result.has_value()) {
1091     TRACE_BROKER_MISSING(broker(), "MapRef::AsElementsKind " << *this);
1092     return {};
1093   }
1094   return MakeRefAssumeMemoryFence(broker(), maybe_result.value());
1095 }
1096 
HasOnlyStablePrototypesWithFastElements(ZoneVector<MapRef> * prototype_maps)1097 bool MapRef::HasOnlyStablePrototypesWithFastElements(
1098     ZoneVector<MapRef>* prototype_maps) {
1099   DCHECK_NOT_NULL(prototype_maps);
1100   MapRef prototype_map = prototype().map();
1101   while (prototype_map.oddball_type() != OddballType::kNull) {
1102     if (!prototype_map.IsJSObjectMap() || !prototype_map.is_stable() ||
1103         !IsFastElementsKind(prototype_map.elements_kind())) {
1104       return false;
1105     }
1106     prototype_maps->push_back(prototype_map);
1107     prototype_map = prototype_map.prototype().map();
1108   }
1109   return true;
1110 }
1111 
supports_fast_array_iteration() const1112 bool MapRef::supports_fast_array_iteration() const {
1113   return SupportsFastArrayIteration(broker(), object());
1114 }
1115 
supports_fast_array_resize() const1116 bool MapRef::supports_fast_array_resize() const {
1117   return SupportsFastArrayResize(broker(), object());
1118 }
1119 
1120 namespace {
1121 
RecordConsistentJSFunctionViewDependencyIfNeeded(const JSHeapBroker * broker,const JSFunctionRef & ref,JSFunctionData * data,JSFunctionData::UsedField used_field)1122 void RecordConsistentJSFunctionViewDependencyIfNeeded(
1123     const JSHeapBroker* broker, const JSFunctionRef& ref, JSFunctionData* data,
1124     JSFunctionData::UsedField used_field) {
1125   if (!data->has_any_used_field()) {
1126     // Deduplicate dependencies.
1127     broker->dependencies()->DependOnConsistentJSFunctionView(ref);
1128   }
1129   data->set_used_field(used_field);
1130 }
1131 
1132 }  // namespace
1133 
feedback_vector(CompilationDependencies * dependencies) const1134 base::Optional<FeedbackVectorRef> JSFunctionRef::feedback_vector(
1135     CompilationDependencies* dependencies) const {
1136   return raw_feedback_cell(dependencies).feedback_vector();
1137 }
1138 
InitialMapInstanceSizeWithMinSlack(CompilationDependencies * dependencies) const1139 int JSFunctionRef::InitialMapInstanceSizeWithMinSlack(
1140     CompilationDependencies* dependencies) const {
1141   if (data_->should_access_heap()) {
1142     return object()->ComputeInstanceSizeWithMinSlack(broker()->isolate());
1143   }
1144   RecordConsistentJSFunctionViewDependencyIfNeeded(
1145       broker(), *this, data()->AsJSFunction(),
1146       JSFunctionData::kInitialMapInstanceSizeWithMinSlack);
1147   return data()->AsJSFunction()->initial_map_instance_size_with_min_slack();
1148 }
1149 
oddball_type() const1150 OddballType MapRef::oddball_type() const {
1151   if (instance_type() != ODDBALL_TYPE) {
1152     return OddballType::kNone;
1153   }
1154   Factory* f = broker()->isolate()->factory();
1155   if (equals(MakeRef(broker(), f->undefined_map()))) {
1156     return OddballType::kUndefined;
1157   }
1158   if (equals(MakeRef(broker(), f->null_map()))) {
1159     return OddballType::kNull;
1160   }
1161   if (equals(MakeRef(broker(), f->boolean_map()))) {
1162     return OddballType::kBoolean;
1163   }
1164   if (equals(MakeRef(broker(), f->the_hole_map()))) {
1165     return OddballType::kHole;
1166   }
1167   if (equals(MakeRef(broker(), f->uninitialized_map()))) {
1168     return OddballType::kUninitialized;
1169   }
1170   DCHECK(equals(MakeRef(broker(), f->termination_exception_map())) ||
1171          equals(MakeRef(broker(), f->arguments_marker_map())) ||
1172          equals(MakeRef(broker(), f->optimized_out_map())) ||
1173          equals(MakeRef(broker(), f->stale_register_map())));
1174   return OddballType::kOther;
1175 }
1176 
GetClosureFeedbackCell(int index) const1177 FeedbackCellRef FeedbackVectorRef::GetClosureFeedbackCell(int index) const {
1178   return MakeRefAssumeMemoryFence(broker(),
1179                                   object()->closure_feedback_cell(index));
1180 }
1181 
raw_properties_or_hash() const1182 base::Optional<ObjectRef> JSObjectRef::raw_properties_or_hash() const {
1183   return TryMakeRef(broker(), object()->raw_properties_or_hash());
1184 }
1185 
RawInobjectPropertyAt(FieldIndex index) const1186 base::Optional<ObjectRef> JSObjectRef::RawInobjectPropertyAt(
1187     FieldIndex index) const {
1188   CHECK(index.is_inobject());
1189   Handle<Object> value;
1190   {
1191     DisallowGarbageCollection no_gc;
1192     PtrComprCageBase cage_base = broker()->cage_base();
1193     Map current_map = object()->map(cage_base, kAcquireLoad);
1194 
1195     // If the map changed in some prior GC epoch, our {index} could be
1196     // outside the valid bounds of the cached map.
1197     if (*map().object() != current_map) {
1198       TRACE_BROKER_MISSING(broker(), "Map change detected in " << *this);
1199       return {};
1200     }
1201 
1202     base::Optional<Object> maybe_value =
1203         object()->RawInobjectPropertyAt(cage_base, current_map, index);
1204     if (!maybe_value.has_value()) {
1205       TRACE_BROKER_MISSING(broker(),
1206                            "Unable to safely read property in " << *this);
1207       return {};
1208     }
1209     value = broker()->CanonicalPersistentHandle(maybe_value.value());
1210   }
1211   return TryMakeRef(broker(), value);
1212 }
1213 
IsElementsTenured(const FixedArrayBaseRef & elements)1214 bool JSObjectRef::IsElementsTenured(const FixedArrayBaseRef& elements) {
1215   return !ObjectInYoungGeneration(*elements.object());
1216 }
1217 
GetFieldIndexFor(InternalIndex descriptor_index) const1218 FieldIndex MapRef::GetFieldIndexFor(InternalIndex descriptor_index) const {
1219   CHECK_LT(descriptor_index.as_int(), NumberOfOwnDescriptors());
1220   FieldIndex result = FieldIndex::ForDescriptor(*object(), descriptor_index);
1221   DCHECK(result.is_inobject());
1222   return result;
1223 }
1224 
GetInObjectPropertyOffset(int i) const1225 int MapRef::GetInObjectPropertyOffset(int i) const {
1226   return object()->GetInObjectPropertyOffset(i);
1227 }
1228 
GetPropertyDetails(InternalIndex descriptor_index) const1229 PropertyDetails MapRef::GetPropertyDetails(
1230     InternalIndex descriptor_index) const {
1231   CHECK_LT(descriptor_index.as_int(), NumberOfOwnDescriptors());
1232   return instance_descriptors().GetPropertyDetails(descriptor_index);
1233 }
1234 
GetPropertyKey(InternalIndex descriptor_index) const1235 NameRef MapRef::GetPropertyKey(InternalIndex descriptor_index) const {
1236   CHECK_LT(descriptor_index.as_int(), NumberOfOwnDescriptors());
1237   return instance_descriptors().GetPropertyKey(descriptor_index);
1238 }
1239 
IsFixedCowArrayMap() const1240 bool MapRef::IsFixedCowArrayMap() const {
1241   Handle<Map> fixed_cow_array_map =
1242       ReadOnlyRoots(broker()->isolate()).fixed_cow_array_map_handle();
1243   return equals(MakeRef(broker(), fixed_cow_array_map));
1244 }
1245 
IsPrimitiveMap() const1246 bool MapRef::IsPrimitiveMap() const {
1247   return instance_type() <= LAST_PRIMITIVE_HEAP_OBJECT_TYPE;
1248 }
1249 
FindFieldOwner(InternalIndex descriptor_index) const1250 MapRef MapRef::FindFieldOwner(InternalIndex descriptor_index) const {
1251   CHECK_LT(descriptor_index.as_int(), NumberOfOwnDescriptors());
1252   // TODO(solanes, v8:7790): Consider caching the result of the field owner on
1253   // the descriptor array. It would be useful for same map as well as any
1254   // other map sharing that descriptor array.
1255   return MakeRefAssumeMemoryFence(
1256       broker(),
1257       object()->FindFieldOwner(broker()->isolate(), descriptor_index));
1258 }
1259 
GetCharAsStringOrUndefined(uint32_t index) const1260 base::Optional<ObjectRef> StringRef::GetCharAsStringOrUndefined(
1261     uint32_t index) const {
1262   String maybe_char;
1263   auto result = ConcurrentLookupIterator::TryGetOwnChar(
1264       &maybe_char, broker()->isolate(), broker()->local_isolate(), *object(),
1265       index);
1266 
1267   if (result == ConcurrentLookupIterator::kGaveUp) {
1268     TRACE_BROKER_MISSING(broker(), "StringRef::GetCharAsStringOrUndefined on "
1269                                        << *this << " at index " << index);
1270     return {};
1271   }
1272 
1273   DCHECK_EQ(result, ConcurrentLookupIterator::kPresent);
1274   return TryMakeRef(broker(), maybe_char);
1275 }
1276 
SupportedStringKind() const1277 bool StringRef::SupportedStringKind() const {
1278   return IsInternalizedString() || object()->IsThinString();
1279 }
1280 
ObjectIfContentAccessible()1281 base::Optional<Handle<String>> StringRef::ObjectIfContentAccessible() {
1282   if (data_->kind() == kNeverSerializedHeapObject && !SupportedStringKind()) {
1283     TRACE_BROKER_MISSING(
1284         broker(),
1285         "content for kNeverSerialized unsupported string kind " << *this);
1286     return base::nullopt;
1287   } else {
1288     return object();
1289   }
1290 }
1291 
length() const1292 base::Optional<int> StringRef::length() const {
1293   if (data_->kind() == kNeverSerializedHeapObject && !SupportedStringKind()) {
1294     TRACE_BROKER_MISSING(
1295         broker(),
1296         "length for kNeverSerialized unsupported string kind " << *this);
1297     return base::nullopt;
1298   } else {
1299     return object()->length(kAcquireLoad);
1300   }
1301 }
1302 
GetFirstChar() const1303 base::Optional<uint16_t> StringRef::GetFirstChar() const { return GetChar(0); }
1304 
GetChar(int index) const1305 base::Optional<uint16_t> StringRef::GetChar(int index) const {
1306   if (data_->kind() == kNeverSerializedHeapObject && !SupportedStringKind()) {
1307     TRACE_BROKER_MISSING(
1308         broker(),
1309         "get char for kNeverSerialized unsupported string kind " << *this);
1310     return base::nullopt;
1311   }
1312 
1313   if (!broker()->IsMainThread()) {
1314     return object()->Get(index, broker()->local_isolate());
1315   } else {
1316     // TODO(solanes, v8:7790): Remove this case once the inlining phase is
1317     // done concurrently all the time.
1318     return object()->Get(index);
1319   }
1320 }
1321 
ToNumber()1322 base::Optional<double> StringRef::ToNumber() {
1323   if (data_->kind() == kNeverSerializedHeapObject && !SupportedStringKind()) {
1324     TRACE_BROKER_MISSING(
1325         broker(),
1326         "number for kNeverSerialized unsupported string kind " << *this);
1327     return base::nullopt;
1328   }
1329 
1330   return TryStringToDouble(broker()->local_isolate(), object());
1331 }
1332 
constants_elements_length() const1333 int ArrayBoilerplateDescriptionRef::constants_elements_length() const {
1334   return object()->constant_elements().length();
1335 }
1336 
TryGet(int i) const1337 base::Optional<ObjectRef> FixedArrayRef::TryGet(int i) const {
1338   Handle<Object> value;
1339   {
1340     DisallowGarbageCollection no_gc;
1341     CHECK_GE(i, 0);
1342     value = broker()->CanonicalPersistentHandle(object()->get(i, kAcquireLoad));
1343     if (i >= object()->length(kAcquireLoad)) {
1344       // Right-trimming happened.
1345       CHECK_LT(i, length());
1346       return {};
1347     }
1348   }
1349   return TryMakeRef(broker(), value);
1350 }
1351 
GetFromImmutableFixedDoubleArray(int i) const1352 Float64 FixedDoubleArrayRef::GetFromImmutableFixedDoubleArray(int i) const {
1353   STATIC_ASSERT(ref_traits<FixedDoubleArray>::ref_serialization_kind ==
1354                 RefSerializationKind::kNeverSerialized);
1355   CHECK(data_->should_access_heap());
1356   return Float64::FromBits(object()->get_representation(i));
1357 }
1358 
SourcePositionTable() const1359 Handle<ByteArray> BytecodeArrayRef::SourcePositionTable() const {
1360   return broker()->CanonicalPersistentHandle(object()->SourcePositionTable());
1361 }
1362 
handler_table_address() const1363 Address BytecodeArrayRef::handler_table_address() const {
1364   return reinterpret_cast<Address>(
1365       object()->handler_table().GetDataStartAddress());
1366 }
1367 
handler_table_size() const1368 int BytecodeArrayRef::handler_table_size() const {
1369   return object()->handler_table().length();
1370 }
1371 
1372 #define IF_ACCESS_FROM_HEAP_C(name)  \
1373   if (data_->should_access_heap()) { \
1374     return object()->name();         \
1375   }
1376 
1377 #define IF_ACCESS_FROM_HEAP(result, name)                     \
1378   if (data_->should_access_heap()) {                          \
1379     return MakeRef(broker(), result::cast(object()->name())); \
1380   }
1381 
1382 // Macros for definining a const getter that, depending on the data kind,
1383 // either looks into the heap or into the serialized data.
1384 #define BIMODAL_ACCESSOR(holder, result, name)                             \
1385   result##Ref holder##Ref::name() const {                                  \
1386     IF_ACCESS_FROM_HEAP(result, name);                                     \
1387     return result##Ref(broker(), ObjectRef::data()->As##holder()->name()); \
1388   }
1389 
1390 // Like above except that the result type is not an XYZRef.
1391 #define BIMODAL_ACCESSOR_C(holder, result, name)    \
1392   result holder##Ref::name() const {                \
1393     IF_ACCESS_FROM_HEAP_C(name);                    \
1394     return ObjectRef::data()->As##holder()->name(); \
1395   }
1396 
1397 // Like above but for BitFields.
1398 #define BIMODAL_ACCESSOR_B(holder, field, name, BitField)              \
1399   typename BitField::FieldType holder##Ref::name() const {             \
1400     IF_ACCESS_FROM_HEAP_C(name);                                       \
1401     return BitField::decode(ObjectRef::data()->As##holder()->field()); \
1402   }
1403 
1404 #define HEAP_ACCESSOR_C(holder, result, name) \
1405   result holder##Ref::name() const { return object()->name(); }
1406 
1407 #define HEAP_ACCESSOR_B(holder, field, name, BitField)     \
1408   typename BitField::FieldType holder##Ref::name() const { \
1409     return object()->name();                               \
1410   }
1411 
nested_site() const1412 ObjectRef AllocationSiteRef::nested_site() const {
1413   return MakeRefAssumeMemoryFence(broker(), object()->nested_site());
1414 }
1415 
HEAP_ACCESSOR_C(AllocationSite,bool,CanInlineCall)1416 HEAP_ACCESSOR_C(AllocationSite, bool, CanInlineCall)
1417 HEAP_ACCESSOR_C(AllocationSite, bool, PointsToLiteral)
1418 HEAP_ACCESSOR_C(AllocationSite, ElementsKind, GetElementsKind)
1419 HEAP_ACCESSOR_C(AllocationSite, AllocationType, GetAllocationType)
1420 
1421 BIMODAL_ACCESSOR_C(BigInt, uint64_t, AsUint64)
1422 
1423 int BytecodeArrayRef::register_count() const {
1424   return object()->register_count();
1425 }
parameter_count() const1426 int BytecodeArrayRef::parameter_count() const {
1427   return object()->parameter_count();
1428 }
1429 interpreter::Register
incoming_new_target_or_generator_register() const1430 BytecodeArrayRef::incoming_new_target_or_generator_register() const {
1431   return object()->incoming_new_target_or_generator_register();
1432 }
1433 
BIMODAL_ACCESSOR(HeapObject,Map,map)1434 BIMODAL_ACCESSOR(HeapObject, Map, map)
1435 
1436 HEAP_ACCESSOR_C(HeapNumber, double, value)
1437 
1438 uint64_t HeapNumberRef::value_as_bits() const {
1439   return object()->value_as_bits(kRelaxedLoad);
1440 }
1441 
bound_target_function() const1442 JSReceiverRef JSBoundFunctionRef::bound_target_function() const {
1443   // Immutable after initialization.
1444   return MakeRefAssumeMemoryFence(broker(), object()->bound_target_function());
1445 }
1446 
bound_this() const1447 ObjectRef JSBoundFunctionRef::bound_this() const {
1448   // Immutable after initialization.
1449   return MakeRefAssumeMemoryFence(broker(), object()->bound_this());
1450 }
1451 
bound_arguments() const1452 FixedArrayRef JSBoundFunctionRef::bound_arguments() const {
1453   // Immutable after initialization.
1454   return MakeRefAssumeMemoryFence(broker(), object()->bound_arguments());
1455 }
1456 
1457 // Immutable after initialization.
HEAP_ACCESSOR_C(JSDataView,size_t,byte_length)1458 HEAP_ACCESSOR_C(JSDataView, size_t, byte_length)
1459 
1460 HEAP_ACCESSOR_B(Map, bit_field2, elements_kind, Map::Bits2::ElementsKindBits)
1461 HEAP_ACCESSOR_B(Map, bit_field3, is_dictionary_map,
1462                 Map::Bits3::IsDictionaryMapBit)
1463 HEAP_ACCESSOR_B(Map, bit_field3, is_deprecated, Map::Bits3::IsDeprecatedBit)
1464 HEAP_ACCESSOR_B(Map, bit_field3, NumberOfOwnDescriptors,
1465                 Map::Bits3::NumberOfOwnDescriptorsBits)
1466 HEAP_ACCESSOR_B(Map, bit_field3, is_migration_target,
1467                 Map::Bits3::IsMigrationTargetBit)
1468 HEAP_ACCESSOR_B(Map, bit_field, has_prototype_slot,
1469                 Map::Bits1::HasPrototypeSlotBit)
1470 HEAP_ACCESSOR_B(Map, bit_field, is_access_check_needed,
1471                 Map::Bits1::IsAccessCheckNeededBit)
1472 HEAP_ACCESSOR_B(Map, bit_field, is_callable, Map::Bits1::IsCallableBit)
1473 HEAP_ACCESSOR_B(Map, bit_field, has_indexed_interceptor,
1474                 Map::Bits1::HasIndexedInterceptorBit)
1475 HEAP_ACCESSOR_B(Map, bit_field, is_constructor, Map::Bits1::IsConstructorBit)
1476 HEAP_ACCESSOR_B(Map, bit_field, is_undetectable, Map::Bits1::IsUndetectableBit)
1477 BIMODAL_ACCESSOR_C(Map, int, instance_size)
1478 HEAP_ACCESSOR_C(Map, int, NextFreePropertyIndex)
1479 BIMODAL_ACCESSOR_C(Map, int, UnusedPropertyFields)
1480 HEAP_ACCESSOR_C(Map, InstanceType, instance_type)
1481 BIMODAL_ACCESSOR_C(Map, bool, is_abandoned_prototype_map)
1482 
1483 int ObjectBoilerplateDescriptionRef::size() const { return object()->size(); }
1484 
BIMODAL_ACCESSOR(PropertyCell,Object,value)1485 BIMODAL_ACCESSOR(PropertyCell, Object, value)
1486 BIMODAL_ACCESSOR_C(PropertyCell, PropertyDetails, property_details)
1487 
1488 FixedArrayRef RegExpBoilerplateDescriptionRef::data() const {
1489   // Immutable after initialization.
1490   return MakeRefAssumeMemoryFence(broker(), object()->data());
1491 }
1492 
source() const1493 StringRef RegExpBoilerplateDescriptionRef::source() const {
1494   // Immutable after initialization.
1495   return MakeRefAssumeMemoryFence(broker(), object()->source());
1496 }
1497 
flags() const1498 int RegExpBoilerplateDescriptionRef::flags() const { return object()->flags(); }
1499 
call_code() const1500 base::Optional<CallHandlerInfoRef> FunctionTemplateInfoRef::call_code() const {
1501   HeapObject call_code = object()->call_code(kAcquireLoad);
1502   if (call_code.IsUndefined()) return base::nullopt;
1503   return TryMakeRef(broker(), CallHandlerInfo::cast(call_code));
1504 }
1505 
is_signature_undefined() const1506 bool FunctionTemplateInfoRef::is_signature_undefined() const {
1507   return object()->signature().IsUndefined(broker()->isolate());
1508 }
1509 
HEAP_ACCESSOR_C(FunctionTemplateInfo,bool,accept_any_receiver)1510 HEAP_ACCESSOR_C(FunctionTemplateInfo, bool, accept_any_receiver)
1511 
1512 HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType(
1513     MapRef receiver_map) {
1514   const HolderLookupResult not_found;
1515   if (!receiver_map.IsJSObjectMap() || (receiver_map.is_access_check_needed() &&
1516                                         !object()->accept_any_receiver())) {
1517     return not_found;
1518   }
1519 
1520   Handle<FunctionTemplateInfo> expected_receiver_type;
1521   {
1522     DisallowGarbageCollection no_gc;
1523     HeapObject signature = object()->signature();
1524     if (signature.IsUndefined()) {
1525       return HolderLookupResult(CallOptimization::kHolderIsReceiver);
1526     }
1527     expected_receiver_type = broker()->CanonicalPersistentHandle(
1528         FunctionTemplateInfo::cast(signature));
1529     if (expected_receiver_type->IsTemplateFor(*receiver_map.object())) {
1530       return HolderLookupResult(CallOptimization::kHolderIsReceiver);
1531     }
1532     if (!receiver_map.IsJSGlobalProxyMap()) return not_found;
1533   }
1534 
1535   HeapObjectRef prototype = receiver_map.prototype();
1536   if (prototype.IsNull()) return not_found;
1537   if (!expected_receiver_type->IsTemplateFor(prototype.object()->map())) {
1538     return not_found;
1539   }
1540   return HolderLookupResult(CallOptimization::kHolderFound,
1541                             prototype.AsJSObject());
1542 }
1543 
data() const1544 ObjectRef CallHandlerInfoRef::data() const {
1545   return MakeRefAssumeMemoryFence(broker(), object()->data());
1546 }
1547 
HEAP_ACCESSOR_C(ScopeInfo,int,ContextLength)1548 HEAP_ACCESSOR_C(ScopeInfo, int, ContextLength)
1549 HEAP_ACCESSOR_C(ScopeInfo, bool, HasContextExtensionSlot)
1550 HEAP_ACCESSOR_C(ScopeInfo, bool, HasOuterScopeInfo)
1551 
1552 ScopeInfoRef ScopeInfoRef::OuterScopeInfo() const {
1553   return MakeRefAssumeMemoryFence(broker(), object()->OuterScopeInfo());
1554 }
1555 
HEAP_ACCESSOR_C(SharedFunctionInfo,Builtin,builtin_id)1556 HEAP_ACCESSOR_C(SharedFunctionInfo, Builtin, builtin_id)
1557 
1558 BytecodeArrayRef SharedFunctionInfoRef::GetBytecodeArray() const {
1559   CHECK(HasBytecodeArray());
1560   BytecodeArray bytecode_array;
1561   if (!broker()->IsMainThread()) {
1562     bytecode_array = object()->GetBytecodeArray(broker()->local_isolate());
1563   } else {
1564     bytecode_array = object()->GetBytecodeArray(broker()->isolate());
1565   }
1566   return MakeRefAssumeMemoryFence(broker(), bytecode_array);
1567 }
1568 
1569 #define DEF_SFI_ACCESSOR(type, name) \
1570   HEAP_ACCESSOR_C(SharedFunctionInfo, type, name)
BROKER_SFI_FIELDS(DEF_SFI_ACCESSOR)1571 BROKER_SFI_FIELDS(DEF_SFI_ACCESSOR)
1572 #undef DEF_SFI_ACCESSOR
1573 
1574 SharedFunctionInfo::Inlineability SharedFunctionInfoRef::GetInlineability()
1575     const {
1576   return broker()->IsMainThread()
1577              ? object()->GetInlineability(broker()->isolate())
1578              : object()->GetInlineability(broker()->local_isolate());
1579 }
1580 
value() const1581 ObjectRef FeedbackCellRef::value() const {
1582   DCHECK(data_->should_access_heap());
1583   return MakeRefAssumeMemoryFence(broker(), object()->value(kAcquireLoad));
1584 }
1585 
GetStrongValue(InternalIndex descriptor_index) const1586 base::Optional<ObjectRef> MapRef::GetStrongValue(
1587     InternalIndex descriptor_index) const {
1588   CHECK_LT(descriptor_index.as_int(), NumberOfOwnDescriptors());
1589   return instance_descriptors().GetStrongValue(descriptor_index);
1590 }
1591 
instance_descriptors() const1592 DescriptorArrayRef MapRef::instance_descriptors() const {
1593   return MakeRefAssumeMemoryFence(
1594       broker(),
1595       object()->instance_descriptors(broker()->isolate(), kAcquireLoad));
1596 }
1597 
prototype() const1598 HeapObjectRef MapRef::prototype() const {
1599   return MakeRefAssumeMemoryFence(broker(),
1600                                   HeapObject::cast(object()->prototype()));
1601 }
1602 
FindRootMap() const1603 MapRef MapRef::FindRootMap() const {
1604   // TODO(solanes, v8:7790): Consider caching the result of the root map.
1605   return MakeRefAssumeMemoryFence(broker(),
1606                                   object()->FindRootMap(broker()->isolate()));
1607 }
1608 
GetConstructor() const1609 ObjectRef MapRef::GetConstructor() const {
1610   // Immutable after initialization.
1611   return MakeRefAssumeMemoryFence(broker(), object()->GetConstructor());
1612 }
1613 
GetBackPointer() const1614 HeapObjectRef MapRef::GetBackPointer() const {
1615   // Immutable after initialization.
1616   return MakeRefAssumeMemoryFence(broker(),
1617                                   HeapObject::cast(object()->GetBackPointer()));
1618 }
1619 
is_on_heap() const1620 bool JSTypedArrayRef::is_on_heap() const {
1621   // Underlying field written 1. during initialization or 2. with release-store.
1622   return object()->is_on_heap(kAcquireLoad);
1623 }
1624 
length() const1625 size_t JSTypedArrayRef::length() const {
1626   CHECK(!is_on_heap());
1627   // Immutable after initialization.
1628   return object()->length();
1629 }
1630 
buffer() const1631 HeapObjectRef JSTypedArrayRef::buffer() const {
1632   CHECK(!is_on_heap());
1633   // Immutable after initialization.
1634   return MakeRef<HeapObject>(broker(), object()->buffer());
1635 }
1636 
data_ptr() const1637 void* JSTypedArrayRef::data_ptr() const {
1638   CHECK(!is_on_heap());
1639   // Underlying field written 1. during initialization or 2. protected by the
1640   // is_on_heap release/acquire semantics (external_pointer store happens-before
1641   // base_pointer store, and this external_pointer load happens-after
1642   // base_pointer load).
1643   STATIC_ASSERT(JSTypedArray::kOffHeapDataPtrEqualsExternalPointer);
1644   return object()->DataPtr();
1645 }
1646 
IsInobjectSlackTrackingInProgress() const1647 bool MapRef::IsInobjectSlackTrackingInProgress() const {
1648   return object()->IsInobjectSlackTrackingInProgress();
1649 }
1650 
constructor_function_index() const1651 int MapRef::constructor_function_index() const {
1652   return object()->GetConstructorFunctionIndex();
1653 }
1654 
is_stable() const1655 bool MapRef::is_stable() const {
1656   IF_ACCESS_FROM_HEAP_C(is_stable);
1657   return !Map::Bits3::IsUnstableBit::decode(data()->AsMap()->bit_field3());
1658 }
1659 
CanBeDeprecated() const1660 bool MapRef::CanBeDeprecated() const { return object()->CanBeDeprecated(); }
1661 
CanTransition() const1662 bool MapRef::CanTransition() const { return object()->CanTransition(); }
1663 
GetInObjectPropertiesStartInWords() const1664 int MapRef::GetInObjectPropertiesStartInWords() const {
1665   return object()->GetInObjectPropertiesStartInWords();
1666 }
1667 
GetInObjectProperties() const1668 int MapRef::GetInObjectProperties() const {
1669   IF_ACCESS_FROM_HEAP_C(GetInObjectProperties);
1670   return data()->AsMap()->in_object_properties();
1671 }
1672 
IsExternalString() const1673 bool StringRef::IsExternalString() const {
1674   return object()->IsExternalString();
1675 }
1676 
callback() const1677 Address CallHandlerInfoRef::callback() const {
1678   return v8::ToCData<Address>(object()->callback());
1679 }
1680 
c_functions() const1681 ZoneVector<Address> FunctionTemplateInfoRef::c_functions() const {
1682   return GetCFunctions(FixedArray::cast(object()->GetCFunctionOverloads()),
1683                        broker()->zone());
1684 }
1685 
c_signatures() const1686 ZoneVector<const CFunctionInfo*> FunctionTemplateInfoRef::c_signatures() const {
1687   return GetCSignatures(FixedArray::cast(object()->GetCFunctionOverloads()),
1688                         broker()->zone());
1689 }
1690 
IsSeqString() const1691 bool StringRef::IsSeqString() const { return object()->IsSeqString(); }
1692 
scope_info() const1693 ScopeInfoRef NativeContextRef::scope_info() const {
1694   // The scope_info is immutable after initialization.
1695   return MakeRefAssumeMemoryFence(broker(), object()->scope_info());
1696 }
1697 
GetFunctionMapFromIndex(int index) const1698 MapRef NativeContextRef::GetFunctionMapFromIndex(int index) const {
1699   DCHECK_GE(index, Context::FIRST_FUNCTION_MAP_INDEX);
1700   DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX);
1701   CHECK_LT(index, object()->length());
1702   return MakeRefAssumeMemoryFence(
1703       broker(), Map::cast(object()->get(index, kAcquireLoad)));
1704 }
1705 
GetInitialJSArrayMap(ElementsKind kind) const1706 MapRef NativeContextRef::GetInitialJSArrayMap(ElementsKind kind) const {
1707   switch (kind) {
1708     case PACKED_SMI_ELEMENTS:
1709       return js_array_packed_smi_elements_map();
1710     case HOLEY_SMI_ELEMENTS:
1711       return js_array_holey_smi_elements_map();
1712     case PACKED_DOUBLE_ELEMENTS:
1713       return js_array_packed_double_elements_map();
1714     case HOLEY_DOUBLE_ELEMENTS:
1715       return js_array_holey_double_elements_map();
1716     case PACKED_ELEMENTS:
1717       return js_array_packed_elements_map();
1718     case HOLEY_ELEMENTS:
1719       return js_array_holey_elements_map();
1720     default:
1721       UNREACHABLE();
1722   }
1723 }
1724 
1725 #define DEF_NATIVE_CONTEXT_ACCESSOR(ResultType, Name)              \
1726   ResultType##Ref NativeContextRef::Name() const {                 \
1727     return MakeRefAssumeMemoryFence(                               \
1728         broker(), ResultType::cast(object()->Name(kAcquireLoad))); \
1729   }
BROKER_NATIVE_CONTEXT_FIELDS(DEF_NATIVE_CONTEXT_ACCESSOR)1730 BROKER_NATIVE_CONTEXT_FIELDS(DEF_NATIVE_CONTEXT_ACCESSOR)
1731 #undef DEF_NATIVE_CONTEXT_ACCESSOR
1732 
1733 base::Optional<JSFunctionRef> NativeContextRef::GetConstructorFunction(
1734     const MapRef& map) const {
1735   CHECK(map.IsPrimitiveMap());
1736   switch (map.constructor_function_index()) {
1737     case Map::kNoConstructorFunctionIndex:
1738       return base::nullopt;
1739     case Context::BIGINT_FUNCTION_INDEX:
1740       return bigint_function();
1741     case Context::BOOLEAN_FUNCTION_INDEX:
1742       return boolean_function();
1743     case Context::NUMBER_FUNCTION_INDEX:
1744       return number_function();
1745     case Context::STRING_FUNCTION_INDEX:
1746       return string_function();
1747     case Context::SYMBOL_FUNCTION_INDEX:
1748       return symbol_function();
1749     default:
1750       UNREACHABLE();
1751   }
1752 }
1753 
IsNull() const1754 bool ObjectRef::IsNull() const { return object()->IsNull(); }
1755 
IsNullOrUndefined() const1756 bool ObjectRef::IsNullOrUndefined() const {
1757   if (IsSmi()) return false;
1758   OddballType type = AsHeapObject().map().oddball_type();
1759   return type == OddballType::kNull || type == OddballType::kUndefined;
1760 }
1761 
IsTheHole() const1762 bool ObjectRef::IsTheHole() const {
1763   return IsHeapObject() &&
1764          AsHeapObject().map().oddball_type() == OddballType::kHole;
1765 }
1766 
TryGetBooleanValue() const1767 base::Optional<bool> ObjectRef::TryGetBooleanValue() const {
1768   if (data_->should_access_heap()) {
1769     return object()->BooleanValue(broker()->isolate());
1770   }
1771   if (IsSmi()) return AsSmi() != 0;
1772   return data()->AsHeapObject()->TryGetBooleanValue(broker());
1773 }
1774 
OddballToNumber() const1775 Maybe<double> ObjectRef::OddballToNumber() const {
1776   OddballType type = AsHeapObject().map().oddball_type();
1777 
1778   switch (type) {
1779     case OddballType::kBoolean: {
1780       ObjectRef true_ref = MakeRef<Object>(
1781           broker(), broker()->isolate()->factory()->true_value());
1782       return this->equals(true_ref) ? Just(1.0) : Just(0.0);
1783     }
1784     case OddballType::kUndefined: {
1785       return Just(std::numeric_limits<double>::quiet_NaN());
1786     }
1787     case OddballType::kNull: {
1788       return Just(0.0);
1789     }
1790     default: {
1791       return Nothing<double>();
1792     }
1793   }
1794 }
1795 
should_access_heap() const1796 bool ObjectRef::should_access_heap() const {
1797   return data()->should_access_heap();
1798 }
1799 
GetOwnConstantElement(const FixedArrayBaseRef & elements_ref,uint32_t index,CompilationDependencies * dependencies) const1800 base::Optional<ObjectRef> JSObjectRef::GetOwnConstantElement(
1801     const FixedArrayBaseRef& elements_ref, uint32_t index,
1802     CompilationDependencies* dependencies) const {
1803   base::Optional<Object> maybe_element = GetOwnConstantElementFromHeap(
1804       *elements_ref.object(), map().elements_kind(), index);
1805   if (!maybe_element.has_value()) return {};
1806 
1807   base::Optional<ObjectRef> result =
1808       TryMakeRef(broker(), maybe_element.value());
1809   if (result.has_value()) {
1810     dependencies->DependOnOwnConstantElement(*this, index, *result);
1811   }
1812   return result;
1813 }
1814 
GetOwnConstantElementFromHeap(FixedArrayBase elements,ElementsKind elements_kind,uint32_t index) const1815 base::Optional<Object> JSObjectRef::GetOwnConstantElementFromHeap(
1816     FixedArrayBase elements, ElementsKind elements_kind, uint32_t index) const {
1817   DCHECK_LE(index, JSObject::kMaxElementIndex);
1818 
1819   Handle<JSObject> holder = object();
1820 
1821   // This block is carefully constructed to avoid Ref creation and access since
1822   // this method may be called after the broker has retired.
1823   // The relaxed `length` read is safe to use in this case since:
1824   // - GetOwnConstantElement only detects a constant for JSArray holders if
1825   //   the array is frozen/sealed.
1826   // - Frozen/sealed arrays can't change length.
1827   // - We've already seen a map with frozen/sealed elements_kinds (above);
1828   // - The release-load of that map ensures we read the newest value
1829   //   of `length` below.
1830   if (holder->IsJSArray()) {
1831     uint32_t array_length;
1832     if (!JSArray::cast(*holder)
1833              .length(broker()->isolate(), kRelaxedLoad)
1834              .ToArrayLength(&array_length)) {
1835       return {};
1836     }
1837     // See also ElementsAccessorBase::GetMaxIndex.
1838     if (index >= array_length) return {};
1839   }
1840 
1841   Object maybe_element;
1842   auto result = ConcurrentLookupIterator::TryGetOwnConstantElement(
1843       &maybe_element, broker()->isolate(), broker()->local_isolate(), *holder,
1844       elements, elements_kind, index);
1845 
1846   if (result == ConcurrentLookupIterator::kGaveUp) {
1847     TRACE_BROKER_MISSING(broker(), "JSObject::GetOwnConstantElement on "
1848                                        << *this << " at index " << index);
1849     return {};
1850   } else if (result == ConcurrentLookupIterator::kNotPresent) {
1851     return {};
1852   }
1853 
1854   DCHECK_EQ(result, ConcurrentLookupIterator::kPresent);
1855   return maybe_element;
1856 }
1857 
GetOwnFastDataProperty(Representation field_representation,FieldIndex index,CompilationDependencies * dependencies) const1858 base::Optional<ObjectRef> JSObjectRef::GetOwnFastDataProperty(
1859     Representation field_representation, FieldIndex index,
1860     CompilationDependencies* dependencies) const {
1861   base::Optional<ObjectRef> result = GetOwnFastDataPropertyFromHeap(
1862       broker(), *this, field_representation, index);
1863   if (result.has_value()) {
1864     dependencies->DependOnOwnConstantDataProperty(
1865         *this, map(), field_representation, index, *result);
1866   }
1867   return result;
1868 }
1869 
GetOwnDictionaryProperty(InternalIndex index,CompilationDependencies * dependencies) const1870 base::Optional<ObjectRef> JSObjectRef::GetOwnDictionaryProperty(
1871     InternalIndex index, CompilationDependencies* dependencies) const {
1872   CHECK(index.is_found());
1873   base::Optional<ObjectRef> result =
1874       GetOwnDictionaryPropertyFromHeap(broker(), object(), index);
1875   if (result.has_value()) {
1876     dependencies->DependOnOwnConstantDictionaryProperty(*this, index, *result);
1877   }
1878   return result;
1879 }
1880 
GetBoilerplateLength() const1881 ObjectRef JSArrayRef::GetBoilerplateLength() const {
1882   // Safe to read concurrently because:
1883   // - boilerplates are immutable after initialization.
1884   // - boilerplates are published into the feedback vector.
1885   // These facts also mean we can expect a valid value.
1886   return length_unsafe().value();
1887 }
1888 
length_unsafe() const1889 base::Optional<ObjectRef> JSArrayRef::length_unsafe() const {
1890   return TryMakeRef(broker(),
1891                     object()->length(broker()->isolate(), kRelaxedLoad));
1892 }
1893 
GetOwnCowElement(FixedArrayBaseRef elements_ref,uint32_t index) const1894 base::Optional<ObjectRef> JSArrayRef::GetOwnCowElement(
1895     FixedArrayBaseRef elements_ref, uint32_t index) const {
1896   // Note: we'd like to check `elements_ref == elements()` here, but due to
1897   // concurrency this may not hold. The code below must be able to deal with
1898   // concurrent `elements` modifications.
1899 
1900   // Due to concurrency, the kind read here may not be consistent with
1901   // `elements_ref`. The caller has to guarantee consistency at runtime by
1902   // other means (e.g. through a runtime equality check or a compilation
1903   // dependency).
1904   ElementsKind elements_kind = map().elements_kind();
1905 
1906   // We only inspect fixed COW arrays, which may only occur for fast
1907   // smi/objects elements kinds.
1908   if (!IsSmiOrObjectElementsKind(elements_kind)) return {};
1909   DCHECK(IsFastElementsKind(elements_kind));
1910   if (!elements_ref.map().IsFixedCowArrayMap()) return {};
1911 
1912   // As the name says, the `length` read here is unsafe and may not match
1913   // `elements`. We rely on the invariant that any `length` change will
1914   // also result in an `elements` change to make this safe. The `elements`
1915   // consistency check in the caller thus also guards the value of `length`.
1916   base::Optional<ObjectRef> length_ref = length_unsafe();
1917 
1918   if (!length_ref.has_value()) return {};
1919 
1920   // Likewise we only deal with smi lengths.
1921   if (!length_ref->IsSmi()) return {};
1922 
1923   base::Optional<Object> result = ConcurrentLookupIterator::TryGetOwnCowElement(
1924       broker()->isolate(), *elements_ref.AsFixedArray().object(), elements_kind,
1925       length_ref->AsSmi(), index);
1926   if (!result.has_value()) return {};
1927 
1928   return TryMakeRef(broker(), result.value());
1929 }
1930 
GetCell(int cell_index) const1931 base::Optional<CellRef> SourceTextModuleRef::GetCell(int cell_index) const {
1932   return TryMakeRef(broker(), object()->GetCell(cell_index));
1933 }
1934 
import_meta() const1935 base::Optional<ObjectRef> SourceTextModuleRef::import_meta() const {
1936   return TryMakeRef(broker(), object()->import_meta(kAcquireLoad));
1937 }
1938 
map_direct_read() const1939 base::Optional<MapRef> HeapObjectRef::map_direct_read() const {
1940   PtrComprCageBase cage_base = broker()->cage_base();
1941   return TryMakeRef(broker(), object()->map(cage_base, kAcquireLoad),
1942                     kAssumeMemoryFence);
1943 }
1944 
1945 namespace {
1946 
GetOddballType(Isolate * isolate,Map map)1947 OddballType GetOddballType(Isolate* isolate, Map map) {
1948   if (map.instance_type() != ODDBALL_TYPE) {
1949     return OddballType::kNone;
1950   }
1951   ReadOnlyRoots roots(isolate);
1952   if (map == roots.undefined_map()) {
1953     return OddballType::kUndefined;
1954   }
1955   if (map == roots.null_map()) {
1956     return OddballType::kNull;
1957   }
1958   if (map == roots.boolean_map()) {
1959     return OddballType::kBoolean;
1960   }
1961   if (map == roots.the_hole_map()) {
1962     return OddballType::kHole;
1963   }
1964   if (map == roots.uninitialized_map()) {
1965     return OddballType::kUninitialized;
1966   }
1967   DCHECK(map == roots.termination_exception_map() ||
1968          map == roots.arguments_marker_map() ||
1969          map == roots.optimized_out_map() || map == roots.stale_register_map());
1970   return OddballType::kOther;
1971 }
1972 
1973 }  // namespace
1974 
GetHeapObjectType() const1975 HeapObjectType HeapObjectRef::GetHeapObjectType() const {
1976   if (data_->should_access_heap()) {
1977     Map map = Handle<HeapObject>::cast(object())->map(broker()->cage_base());
1978     HeapObjectType::Flags flags(0);
1979     if (map.is_undetectable()) flags |= HeapObjectType::kUndetectable;
1980     if (map.is_callable()) flags |= HeapObjectType::kCallable;
1981     return HeapObjectType(map.instance_type(), flags,
1982                           GetOddballType(broker()->isolate(), map));
1983   }
1984   HeapObjectType::Flags flags(0);
1985   if (map().is_undetectable()) flags |= HeapObjectType::kUndetectable;
1986   if (map().is_callable()) flags |= HeapObjectType::kCallable;
1987   return HeapObjectType(map().instance_type(), flags, map().oddball_type());
1988 }
1989 
boilerplate() const1990 base::Optional<JSObjectRef> AllocationSiteRef::boilerplate() const {
1991   if (!PointsToLiteral()) return {};
1992   DCHECK(data_->should_access_heap());
1993   return TryMakeRef(broker(), object()->boilerplate(kAcquireLoad));
1994 }
1995 
elements(RelaxedLoadTag tag) const1996 base::Optional<FixedArrayBaseRef> JSObjectRef::elements(
1997     RelaxedLoadTag tag) const {
1998   return TryMakeRef(broker(), object()->elements(tag));
1999 }
2000 
length() const2001 int FixedArrayBaseRef::length() const {
2002   IF_ACCESS_FROM_HEAP_C(length);
2003   return data()->AsFixedArrayBase()->length();
2004 }
2005 
GetPropertyDetails(InternalIndex descriptor_index) const2006 PropertyDetails DescriptorArrayRef::GetPropertyDetails(
2007     InternalIndex descriptor_index) const {
2008   return object()->GetDetails(descriptor_index);
2009 }
2010 
GetPropertyKey(InternalIndex descriptor_index) const2011 NameRef DescriptorArrayRef::GetPropertyKey(
2012     InternalIndex descriptor_index) const {
2013   NameRef result = MakeRef(broker(), object()->GetKey(descriptor_index));
2014   CHECK(result.IsUniqueName());
2015   return result;
2016 }
2017 
GetStrongValue(InternalIndex descriptor_index) const2018 base::Optional<ObjectRef> DescriptorArrayRef::GetStrongValue(
2019     InternalIndex descriptor_index) const {
2020   HeapObject heap_object;
2021   if (!object()
2022            ->GetValue(descriptor_index)
2023            .GetHeapObjectIfStrong(&heap_object)) {
2024     return {};
2025   }
2026   // Since the descriptors in the descriptor array can be changed in-place
2027   // via DescriptorArray::Replace, we might get a value that we haven't seen
2028   // before.
2029   return TryMakeRef(broker(), heap_object);
2030 }
2031 
feedback_vector() const2032 base::Optional<FeedbackVectorRef> FeedbackCellRef::feedback_vector() const {
2033   ObjectRef contents = value();
2034   if (!contents.IsFeedbackVector()) return {};
2035   return contents.AsFeedbackVector();
2036 }
2037 
shared_function_info() const2038 base::Optional<SharedFunctionInfoRef> FeedbackCellRef::shared_function_info()
2039     const {
2040   base::Optional<FeedbackVectorRef> vector = feedback_vector();
2041   if (!vector.has_value()) return {};
2042   return vector->shared_function_info();
2043 }
2044 
shared_function_info() const2045 SharedFunctionInfoRef FeedbackVectorRef::shared_function_info() const {
2046   // Immutable after initialization.
2047   return MakeRefAssumeMemoryFence(broker(), object()->shared_function_info());
2048 }
2049 
IsUniqueName() const2050 bool NameRef::IsUniqueName() const {
2051   // Must match Name::IsUniqueName.
2052   return IsInternalizedString() || IsSymbol();
2053 }
2054 
object() const2055 Handle<Object> ObjectRef::object() const {
2056   return data_->object();
2057 }
2058 
2059 #ifdef DEBUG
2060 #define DEF_OBJECT_GETTER(T)                                                 \
2061   Handle<T> T##Ref::object() const {                                         \
2062     return Handle<T>(reinterpret_cast<Address*>(data_->object().address())); \
2063   }
2064 #else
2065 #define DEF_OBJECT_GETTER(T)                                                 \
2066   Handle<T> T##Ref::object() const {                                         \
2067     return Handle<T>(reinterpret_cast<Address*>(data_->object().address())); \
2068   }
2069 #endif  // DEBUG
2070 
HEAP_BROKER_OBJECT_LIST(DEF_OBJECT_GETTER)2071 HEAP_BROKER_OBJECT_LIST(DEF_OBJECT_GETTER)
2072 #undef DEF_OBJECT_GETTER
2073 
2074 JSHeapBroker* ObjectRef::broker() const { return broker_; }
2075 
data() const2076 ObjectData* ObjectRef::data() const {
2077   switch (broker()->mode()) {
2078     case JSHeapBroker::kDisabled:
2079       return data_;
2080     case JSHeapBroker::kSerializing:
2081       CHECK_NE(data_->kind(), kUnserializedHeapObject);
2082       return data_;
2083     case JSHeapBroker::kSerialized:
2084     case JSHeapBroker::kRetired:
2085       CHECK_NE(data_->kind(), kUnserializedHeapObject);
2086       return data_;
2087   }
2088 }
2089 
2090 template <class T>
AsRef(JSHeapBroker * broker) const2091 typename TinyRef<T>::RefType TinyRef<T>::AsRef(JSHeapBroker* broker) const {
2092   if (data_->kind() == kUnserializedHeapObject &&
2093       broker->mode() != JSHeapBroker::kDisabled) {
2094     // Gotta reconstruct to avoid returning a stale unserialized ref.
2095     return MakeRefAssumeMemoryFence<T>(broker,
2096                                        Handle<T>::cast(data_->object()));
2097   }
2098   return TryMakeRef<T>(broker, data_).value();
2099 }
2100 
2101 template <class T>
object() const2102 Handle<T> TinyRef<T>::object() const {
2103   return Handle<T>::cast(data_->object());
2104 }
2105 
2106 #define V(Name)                                  \
2107   template class TinyRef<Name>;                  \
2108   /* TinyRef should contain only one pointer. */ \
2109   STATIC_ASSERT(sizeof(TinyRef<Name>) == kSystemPointerSize);
2110 HEAP_BROKER_OBJECT_LIST(V)
2111 #undef V
2112 
2113 #define JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP(Result, Name, UsedField)    \
2114   Result##Ref JSFunctionRef::Name(CompilationDependencies* dependencies) \
2115       const {                                                            \
2116     IF_ACCESS_FROM_HEAP(Result, Name);                                   \
2117     RecordConsistentJSFunctionViewDependencyIfNeeded(                    \
2118         broker(), *this, data()->AsJSFunction(), UsedField);             \
2119     return Result##Ref(broker(), data()->AsJSFunction()->Name());        \
2120   }
2121 
2122 #define JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP_C(Result, Name, UsedField)     \
2123   Result JSFunctionRef::Name(CompilationDependencies* dependencies) const { \
2124     IF_ACCESS_FROM_HEAP_C(Name);                                            \
2125     RecordConsistentJSFunctionViewDependencyIfNeeded(                       \
2126         broker(), *this, data()->AsJSFunction(), UsedField);                \
2127     return data()->AsJSFunction()->Name();                                  \
2128   }
2129 
2130 // Like JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP_C but only depend on the
2131 // field in question if its recorded value is "relevant". This is in order to
2132 // tolerate certain state changes during compilation, e.g. from "has no feedback
2133 // vector" (in which case we would simply do less optimization) to "has feedback
2134 // vector".
2135 #define JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP_RELEVANT_C(                    \
2136     Result, Name, UsedField, RelevantValue)                                 \
2137   Result JSFunctionRef::Name(CompilationDependencies* dependencies) const { \
2138     IF_ACCESS_FROM_HEAP_C(Name);                                            \
2139     Result const result = data()->AsJSFunction()->Name();                   \
2140     if (result == RelevantValue) {                                          \
2141       RecordConsistentJSFunctionViewDependencyIfNeeded(                     \
2142           broker(), *this, data()->AsJSFunction(), UsedField);              \
2143     }                                                                       \
2144     return result;                                                          \
2145   }
2146 
JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP_RELEVANT_C(bool,has_initial_map,JSFunctionData::kHasInitialMap,true)2147 JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP_RELEVANT_C(bool, has_initial_map,
2148                                                 JSFunctionData::kHasInitialMap,
2149                                                 true)
2150 JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP_RELEVANT_C(
2151     bool, has_instance_prototype, JSFunctionData::kHasInstancePrototype, true)
2152 JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP_RELEVANT_C(
2153     bool, PrototypeRequiresRuntimeLookup,
2154     JSFunctionData::kPrototypeRequiresRuntimeLookup, false)
2155 
2156 JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP(Map, initial_map,
2157                                      JSFunctionData::kInitialMap)
2158 JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP(Object, instance_prototype,
2159                                      JSFunctionData::kInstancePrototype)
2160 JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP(FeedbackCell, raw_feedback_cell,
2161                                      JSFunctionData::kFeedbackCell)
2162 
2163 BIMODAL_ACCESSOR(JSFunction, Context, context)
2164 BIMODAL_ACCESSOR(JSFunction, SharedFunctionInfo, shared)
2165 
2166 #undef JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP
2167 #undef JSFUNCTION_BIMODAL_ACCESSOR_WITH_DEP_C
2168 
2169 CodeRef JSFunctionRef::code() const {
2170   CodeT code = object()->code(kAcquireLoad);
2171   // Safe to do a relaxed conversion to Code here since CodeT::code field is
2172   // modified only by GC and the CodeT was acquire-loaded.
2173   return MakeRefAssumeMemoryFence(broker(), FromCodeT(code, kRelaxedLoad));
2174 }
2175 
native_context() const2176 NativeContextRef JSFunctionRef::native_context() const {
2177   return MakeRefAssumeMemoryFence(broker(),
2178                                   context().object()->native_context());
2179 }
2180 
2181 base::Optional<FunctionTemplateInfoRef>
function_template_info() const2182 SharedFunctionInfoRef::function_template_info() const {
2183   if (!object()->IsApiFunction()) return {};
2184   return TryMakeRef(broker(), FunctionTemplateInfo::cast(
2185                                   object()->function_data(kAcquireLoad)));
2186 }
2187 
context_header_size() const2188 int SharedFunctionInfoRef::context_header_size() const {
2189   return object()->scope_info().ContextHeaderLength();
2190 }
2191 
context_parameters_start() const2192 int SharedFunctionInfoRef::context_parameters_start() const {
2193   return object()->scope_info().ParametersStartIndex();
2194 }
2195 
scope_info() const2196 ScopeInfoRef SharedFunctionInfoRef::scope_info() const {
2197   return MakeRefAssumeMemoryFence(broker(), object()->scope_info(kAcquireLoad));
2198 }
2199 
GetObjectCreateMap() const2200 base::Optional<MapRef> JSObjectRef::GetObjectCreateMap() const {
2201   Handle<Map> map_handle = Handle<Map>::cast(map().object());
2202   // Note: implemented as an acquire-load.
2203   if (!map_handle->is_prototype_map()) return {};
2204 
2205   Handle<Object> maybe_proto_info = broker()->CanonicalPersistentHandle(
2206       map_handle->prototype_info(kAcquireLoad));
2207   if (!maybe_proto_info->IsPrototypeInfo()) return {};
2208 
2209   MaybeObject maybe_object_create_map =
2210       Handle<PrototypeInfo>::cast(maybe_proto_info)
2211           ->object_create_map(kAcquireLoad);
2212   if (!maybe_object_create_map->IsWeak()) return {};
2213 
2214   return MapRef(broker(),
2215                 broker()->GetOrCreateData(
2216                     maybe_object_create_map->GetHeapObjectAssumeWeak(),
2217                     kAssumeMemoryFence));
2218 }
2219 
Cache() const2220 bool PropertyCellRef::Cache() const {
2221   if (data_->should_access_heap()) return true;
2222   CHECK(broker()->mode() == JSHeapBroker::kSerializing ||
2223         broker()->mode() == JSHeapBroker::kSerialized);
2224   return data()->AsPropertyCell()->Cache(broker());
2225 }
2226 
GlobalIsDetached() const2227 bool NativeContextRef::GlobalIsDetached() const {
2228   ObjectRef proxy_proto = global_proxy_object().map().prototype();
2229   return !proxy_proto.equals(global_object());
2230 }
2231 
GetPropertyCell(NameRef const & name) const2232 base::Optional<PropertyCellRef> JSGlobalObjectRef::GetPropertyCell(
2233     NameRef const& name) const {
2234   base::Optional<PropertyCell> maybe_cell =
2235       ConcurrentLookupIterator::TryGetPropertyCell(
2236           broker()->isolate(), broker()->local_isolate_or_isolate(),
2237           broker()->target_native_context().global_object().object(),
2238           name.object());
2239   if (!maybe_cell.has_value()) return {};
2240   return TryMakeRef(broker(), *maybe_cell);
2241 }
2242 
operator <<(std::ostream & os,const ObjectRef & ref)2243 std::ostream& operator<<(std::ostream& os, const ObjectRef& ref) {
2244   if (!FLAG_concurrent_recompilation) {
2245     // We cannot be in a background thread so it's safe to read the heap.
2246     AllowHandleDereference allow_handle_dereference;
2247     return os << ref.data() << " {" << ref.object() << "}";
2248   } else if (ref.data_->should_access_heap()) {
2249     return os << ref.data() << " {" << ref.object() << "}";
2250   } else {
2251     return os << ref.data();
2252   }
2253 }
2254 
GetInlinedBytecodeSize() const2255 unsigned CodeRef::GetInlinedBytecodeSize() const {
2256   unsigned value = object()->inlined_bytecode_size();
2257   if (value > 0) {
2258     // Don't report inlined bytecode size if the code object was already
2259     // deoptimized.
2260     value = object()->marked_for_deoptimization() ? 0 : value;
2261   }
2262   return value;
2263 }
2264 
2265 #undef BIMODAL_ACCESSOR
2266 #undef BIMODAL_ACCESSOR_B
2267 #undef BIMODAL_ACCESSOR_C
2268 #undef HEAP_ACCESSOR_B
2269 #undef HEAP_ACCESSOR_C
2270 #undef IF_ACCESS_FROM_HEAP
2271 #undef IF_ACCESS_FROM_HEAP_C
2272 #undef TRACE
2273 #undef TRACE_MISSING
2274 
2275 }  // namespace compiler
2276 }  // namespace internal
2277 }  // namespace v8
2278