• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_COMPILER_JS_HEAP_BROKER_H_
6 #define V8_COMPILER_JS_HEAP_BROKER_H_
7 
8 #include "src/base/compiler-specific.h"
9 #include "src/base/optional.h"
10 #include "src/base/platform/mutex.h"
11 #include "src/common/globals.h"
12 #include "src/compiler/access-info.h"
13 #include "src/compiler/feedback-source.h"
14 #include "src/compiler/globals.h"
15 #include "src/compiler/heap-refs.h"
16 #include "src/compiler/processed-feedback.h"
17 #include "src/compiler/refs-map.h"
18 #include "src/execution/local-isolate.h"
19 #include "src/handles/handles.h"
20 #include "src/handles/persistent-handles.h"
21 #include "src/heap/local-heap.h"
22 #include "src/heap/parked-scope.h"
23 #include "src/interpreter/bytecode-array-iterator.h"
24 #include "src/objects/code-kind.h"
25 #include "src/objects/feedback-vector.h"
26 #include "src/objects/function-kind.h"
27 #include "src/objects/objects.h"
28 #include "src/utils/address-map.h"
29 #include "src/utils/identity-map.h"
30 #include "src/utils/ostreams.h"
31 #include "src/zone/zone-containers.h"
32 
33 namespace v8 {
34 namespace internal {
35 
36 namespace maglev {
37 class MaglevCompilationInfo;
38 }
39 
40 namespace compiler {
41 
42 class ObjectRef;
43 
44 std::ostream& operator<<(std::ostream& os, const ObjectRef& ref);
45 
46 #define TRACE_BROKER(broker, x)                                      \
47   do {                                                               \
48     if (broker->tracing_enabled() && FLAG_trace_heap_broker_verbose) \
49       StdoutStream{} << broker->Trace() << x << '\n';                \
50   } while (false)
51 
52 #define TRACE_BROKER_MEMORY(broker, x)                              \
53   do {                                                              \
54     if (broker->tracing_enabled() && FLAG_trace_heap_broker_memory) \
55       StdoutStream{} << broker->Trace() << x << std::endl;          \
56   } while (false)
57 
58 #define TRACE_BROKER_MISSING(broker, x)                                        \
59   do {                                                                         \
60     if (broker->tracing_enabled())                                             \
61       StdoutStream{} << broker->Trace() << "Missing " << x << " (" << __FILE__ \
62                      << ":" << __LINE__ << ")" << std::endl;                   \
63   } while (false)
64 
65 struct PropertyAccessTarget {
66   MapRef map;
67   NameRef name;
68   AccessMode mode;
69 
70   struct Hash {
operatorPropertyAccessTarget::Hash71     size_t operator()(const PropertyAccessTarget& pair) const {
72       return base::hash_combine(
73           base::hash_combine(pair.map.object().address(),
74                              pair.name.object().address()),
75           static_cast<int>(pair.mode));
76     }
77   };
78   struct Equal {
operatorPropertyAccessTarget::Equal79     bool operator()(const PropertyAccessTarget& lhs,
80                     const PropertyAccessTarget& rhs) const {
81       return lhs.map.equals(rhs.map) && lhs.name.equals(rhs.name) &&
82              lhs.mode == rhs.mode;
83     }
84   };
85 };
86 
87 enum GetOrCreateDataFlag {
88   // If set, a failure to create the data object results in a crash.
89   kCrashOnError = 1 << 0,
90   // If set, data construction assumes that the given object is protected by
91   // a memory fence (e.g. acquire-release) and thus fields required for
92   // construction (like Object::map) are safe to read. The protection can
93   // extend to some other situations as well.
94   kAssumeMemoryFence = 1 << 1,
95 };
96 using GetOrCreateDataFlags = base::Flags<GetOrCreateDataFlag>;
DEFINE_OPERATORS_FOR_FLAGS(GetOrCreateDataFlags)97 DEFINE_OPERATORS_FOR_FLAGS(GetOrCreateDataFlags)
98 
99 class V8_EXPORT_PRIVATE JSHeapBroker {
100  public:
101   JSHeapBroker(Isolate* isolate, Zone* broker_zone, bool tracing_enabled,
102                CodeKind code_kind);
103 
104   // For use only in tests, sets default values for some arguments. Avoids
105   // churn when new flags are added.
106   JSHeapBroker(Isolate* isolate, Zone* broker_zone)
107       : JSHeapBroker(isolate, broker_zone, FLAG_trace_heap_broker,
108                      CodeKind::TURBOFAN) {}
109 
110   ~JSHeapBroker();
111 
112   // The compilation target's native context. We need the setter because at
113   // broker construction time we don't yet have the canonical handle.
114   NativeContextRef target_native_context() const {
115     return target_native_context_.value();
116   }
117   void SetTargetNativeContextRef(Handle<NativeContext> native_context);
118 
119   void InitializeAndStartSerializing();
120 
121   Isolate* isolate() const { return isolate_; }
122 
123   // The pointer compression cage base value used for decompression of all
124   // tagged values except references to Code objects.
125   PtrComprCageBase cage_base() const {
126 #if V8_COMPRESS_POINTERS
127     return cage_base_;
128 #else
129     return PtrComprCageBase{};
130 #endif  // V8_COMPRESS_POINTERS
131   }
132 
133   Zone* zone() const { return zone_; }
134   bool tracing_enabled() const { return tracing_enabled_; }
135 
136   NexusConfig feedback_nexus_config() const {
137     return IsMainThread() ? NexusConfig::FromMainThread(isolate())
138                           : NexusConfig::FromBackgroundThread(
139                                 isolate(), local_isolate()->heap());
140   }
141 
142   enum BrokerMode { kDisabled, kSerializing, kSerialized, kRetired };
143   BrokerMode mode() const { return mode_; }
144 
145   void StopSerializing();
146   void Retire();
147   bool SerializingAllowed() const;
148 
149   // Remember the local isolate and initialize its local heap with the
150   // persistent and canonical handles provided by {info}.
151   void AttachLocalIsolate(OptimizedCompilationInfo* info,
152                           LocalIsolate* local_isolate);
153   // Forget about the local isolate and pass the persistent and canonical
154   // handles provided back to {info}. {info} is responsible for disposing of
155   // them.
156   void DetachLocalIsolate(OptimizedCompilationInfo* info);
157 
158   // TODO(v8:7700): Refactor this once the broker is no longer
159   // Turbofan-specific.
160   void AttachLocalIsolateForMaglev(maglev::MaglevCompilationInfo* info,
161                                    LocalIsolate* local_isolate);
162   void DetachLocalIsolateForMaglev(maglev::MaglevCompilationInfo* info);
163 
164   bool StackHasOverflowed() const;
165 
166 #ifdef DEBUG
167   void PrintRefsAnalysis() const;
168 #endif  // DEBUG
169 
170   // Returns the handle from root index table for read only heap objects.
171   Handle<Object> GetRootHandle(Object object);
172 
173   // Never returns nullptr.
174   ObjectData* GetOrCreateData(Handle<Object> object,
175                               GetOrCreateDataFlags flags = {});
176   ObjectData* GetOrCreateData(Object object, GetOrCreateDataFlags flags = {});
177 
178   // Gets data only if we have it. However, thin wrappers will be created for
179   // smis, read-only objects and never-serialized objects.
180   ObjectData* TryGetOrCreateData(Handle<Object> object,
181                                  GetOrCreateDataFlags flags = {});
182   ObjectData* TryGetOrCreateData(Object object,
183                                  GetOrCreateDataFlags flags = {});
184 
185   // Check if {object} is any native context's %ArrayPrototype% or
186   // %ObjectPrototype%.
187   bool IsArrayOrObjectPrototype(const JSObjectRef& object) const;
188   bool IsArrayOrObjectPrototype(Handle<JSObject> object) const;
189 
190   bool HasFeedback(FeedbackSource const& source) const;
191   void SetFeedback(FeedbackSource const& source,
192                    ProcessedFeedback const* feedback);
193   FeedbackSlotKind GetFeedbackSlotKind(FeedbackSource const& source) const;
194 
195   ElementAccessFeedback const& ProcessFeedbackMapsForElementAccess(
196       ZoneVector<MapRef>& maps, KeyedAccessMode const& keyed_mode,
197       FeedbackSlotKind slot_kind);
198 
199   // Binary, comparison and for-in hints can be fully expressed via
200   // an enum. Insufficient feedback is signaled by <Hint enum>::kNone.
201   BinaryOperationHint GetFeedbackForBinaryOperation(
202       FeedbackSource const& source);
203   CompareOperationHint GetFeedbackForCompareOperation(
204       FeedbackSource const& source);
205   ForInHint GetFeedbackForForIn(FeedbackSource const& source);
206 
207   ProcessedFeedback const& GetFeedbackForCall(FeedbackSource const& source);
208   ProcessedFeedback const& GetFeedbackForGlobalAccess(
209       FeedbackSource const& source);
210   ProcessedFeedback const& GetFeedbackForInstanceOf(
211       FeedbackSource const& source);
212   ProcessedFeedback const& GetFeedbackForArrayOrObjectLiteral(
213       FeedbackSource const& source);
214   ProcessedFeedback const& GetFeedbackForRegExpLiteral(
215       FeedbackSource const& source);
216   ProcessedFeedback const& GetFeedbackForTemplateObject(
217       FeedbackSource const& source);
218   ProcessedFeedback const& GetFeedbackForPropertyAccess(
219       FeedbackSource const& source, AccessMode mode,
220       base::Optional<NameRef> static_name);
221 
222   ProcessedFeedback const& ProcessFeedbackForBinaryOperation(
223       FeedbackSource const& source);
224   ProcessedFeedback const& ProcessFeedbackForCompareOperation(
225       FeedbackSource const& source);
226   ProcessedFeedback const& ProcessFeedbackForForIn(
227       FeedbackSource const& source);
228 
229   bool FeedbackIsInsufficient(FeedbackSource const& source) const;
230 
231   base::Optional<NameRef> GetNameFeedback(FeedbackNexus const& nexus);
232 
233   PropertyAccessInfo GetPropertyAccessInfo(
234       MapRef map, NameRef name, AccessMode access_mode,
235       CompilationDependencies* dependencies);
236 
237   StringRef GetTypedArrayStringTag(ElementsKind kind);
238 
239   bool IsMainThread() const {
240     return local_isolate() == nullptr || local_isolate()->is_main_thread();
241   }
242 
243   LocalIsolate* local_isolate() const { return local_isolate_; }
244 
245   // TODO(jgruber): Consider always having local_isolate_ set to a real value.
246   // This seems not entirely trivial since we currently reset local_isolate_ to
247   // nullptr at some point in the JSHeapBroker lifecycle.
248   LocalIsolate* local_isolate_or_isolate() const {
249     return local_isolate() != nullptr ? local_isolate()
250                                       : isolate()->AsLocalIsolate();
251   }
252 
253   // Return the corresponding canonical persistent handle for {object}. Create
254   // one if it does not exist.
255   // If we have the canonical map, we can create the canonical & persistent
256   // handle through it. This commonly happens during the Execute phase.
257   // If we don't, that means we are calling this method from serialization. If
258   // that happens, we should be inside a canonical and a persistent handle
259   // scope. Then, we would just use the regular handle creation.
260   template <typename T>
261   Handle<T> CanonicalPersistentHandle(T object) {
262     if (canonical_handles_) {
263       Address address = object.ptr();
264       if (Internals::HasHeapObjectTag(address)) {
265         RootIndex root_index;
266         if (root_index_map_.Lookup(address, &root_index)) {
267           return Handle<T>(isolate_->root_handle(root_index).location());
268         }
269       }
270 
271       Object obj(address);
272       auto find_result = canonical_handles_->FindOrInsert(obj);
273       if (!find_result.already_exists) {
274         // Allocate new PersistentHandle if one wasn't created before.
275         DCHECK_NOT_NULL(local_isolate());
276         *find_result.entry =
277             local_isolate()->heap()->NewPersistentHandle(obj).location();
278       }
279       return Handle<T>(*find_result.entry);
280     } else {
281       return Handle<T>(object, isolate());
282     }
283   }
284 
285   template <typename T>
286   Handle<T> CanonicalPersistentHandle(Handle<T> object) {
287     if (object.is_null()) return object;  // Can't deref a null handle.
288     return CanonicalPersistentHandle<T>(*object);
289   }
290 
291   // Find the corresponding handle in the CanonicalHandlesMap. The entry must be
292   // found.
293   template <typename T>
294   Handle<T> FindCanonicalPersistentHandleForTesting(Object object) {
295     Address** entry = canonical_handles_->Find(object);
296     return Handle<T>(*entry);
297   }
298 
299   // Set the persistent handles and copy the canonical handles over to the
300   // JSHeapBroker.
301   void SetPersistentAndCopyCanonicalHandlesForTesting(
302       std::unique_ptr<PersistentHandles> persistent_handles,
303       std::unique_ptr<CanonicalHandlesMap> canonical_handles);
304   std::string Trace() const;
305   void IncrementTracingIndentation();
306   void DecrementTracingIndentation();
307 
308   // Locks {mutex} through the duration of this scope iff it is the first
309   // occurrence. This is done to have a recursive shared lock on {mutex}.
310   class V8_NODISCARD RecursiveSharedMutexGuardIfNeeded {
311    protected:
312     RecursiveSharedMutexGuardIfNeeded(LocalIsolate* local_isolate,
313                                       base::SharedMutex* mutex,
314                                       int* mutex_depth_address)
315         : mutex_depth_address_(mutex_depth_address),
316           initial_mutex_depth_(*mutex_depth_address_),
317           shared_mutex_guard_(local_isolate, mutex, initial_mutex_depth_ == 0) {
318       (*mutex_depth_address_)++;
319     }
320 
321     ~RecursiveSharedMutexGuardIfNeeded() {
322       DCHECK_GE((*mutex_depth_address_), 1);
323       (*mutex_depth_address_)--;
324       DCHECK_EQ(initial_mutex_depth_, (*mutex_depth_address_));
325     }
326 
327    private:
328     int* const mutex_depth_address_;
329     const int initial_mutex_depth_;
330     ParkedSharedMutexGuardIf<base::kShared> shared_mutex_guard_;
331   };
332 
333   class MapUpdaterGuardIfNeeded final
334       : public RecursiveSharedMutexGuardIfNeeded {
335    public:
336     explicit MapUpdaterGuardIfNeeded(JSHeapBroker* broker)
337         : RecursiveSharedMutexGuardIfNeeded(
338               broker->local_isolate_or_isolate(),
339               broker->isolate()->map_updater_access(),
340               &broker->map_updater_mutex_depth_) {}
341   };
342 
343   class BoilerplateMigrationGuardIfNeeded final
344       : public RecursiveSharedMutexGuardIfNeeded {
345    public:
346     explicit BoilerplateMigrationGuardIfNeeded(JSHeapBroker* broker)
347         : RecursiveSharedMutexGuardIfNeeded(
348               broker->local_isolate_or_isolate(),
349               broker->isolate()->boilerplate_migration_access(),
350               &broker->boilerplate_migration_mutex_depth_) {}
351   };
352 
353   // If this returns false, the object is guaranteed to be fully initialized and
354   // thus safe to read from a memory safety perspective. The converse does not
355   // necessarily hold.
356   bool ObjectMayBeUninitialized(Handle<Object> object) const;
357   bool ObjectMayBeUninitialized(Object object) const;
358   bool ObjectMayBeUninitialized(HeapObject object) const;
359 
360   void set_dependencies(CompilationDependencies* dependencies) {
361     DCHECK_NOT_NULL(dependencies);
362     DCHECK_NULL(dependencies_);
363     dependencies_ = dependencies;
364   }
365   CompilationDependencies* dependencies() const {
366     DCHECK_NOT_NULL(dependencies_);
367     return dependencies_;
368   }
369 
370  private:
371   friend class HeapObjectRef;
372   friend class ObjectRef;
373   friend class ObjectData;
374   friend class PropertyCellData;
375 
376   ProcessedFeedback const& GetFeedback(FeedbackSource const& source) const;
377   const ProcessedFeedback& NewInsufficientFeedback(FeedbackSlotKind kind) const;
378 
379   // Bottleneck FeedbackNexus access here, for storage in the broker
380   // or on-the-fly usage elsewhere in the compiler.
381   ProcessedFeedback const& ReadFeedbackForArrayOrObjectLiteral(
382       FeedbackSource const& source);
383   ProcessedFeedback const& ReadFeedbackForBinaryOperation(
384       FeedbackSource const& source) const;
385   ProcessedFeedback const& ReadFeedbackForCall(FeedbackSource const& source);
386   ProcessedFeedback const& ReadFeedbackForCompareOperation(
387       FeedbackSource const& source) const;
388   ProcessedFeedback const& ReadFeedbackForForIn(
389       FeedbackSource const& source) const;
390   ProcessedFeedback const& ReadFeedbackForGlobalAccess(
391       FeedbackSource const& source);
392   ProcessedFeedback const& ReadFeedbackForInstanceOf(
393       FeedbackSource const& source);
394   ProcessedFeedback const& ReadFeedbackForPropertyAccess(
395       FeedbackSource const& source, AccessMode mode,
396       base::Optional<NameRef> static_name);
397   ProcessedFeedback const& ReadFeedbackForRegExpLiteral(
398       FeedbackSource const& source);
399   ProcessedFeedback const& ReadFeedbackForTemplateObject(
400       FeedbackSource const& source);
401 
402   void CollectArrayAndObjectPrototypes();
403 
404   void set_persistent_handles(
405       std::unique_ptr<PersistentHandles> persistent_handles) {
406     DCHECK_NULL(ph_);
407     ph_ = std::move(persistent_handles);
408     DCHECK_NOT_NULL(ph_);
409   }
410   std::unique_ptr<PersistentHandles> DetachPersistentHandles() {
411     DCHECK_NOT_NULL(ph_);
412     return std::move(ph_);
413   }
414 
415   void set_canonical_handles(
416       std::unique_ptr<CanonicalHandlesMap> canonical_handles) {
417     DCHECK_NULL(canonical_handles_);
418     canonical_handles_ = std::move(canonical_handles);
419     DCHECK_NOT_NULL(canonical_handles_);
420   }
421 
422   std::unique_ptr<CanonicalHandlesMap> DetachCanonicalHandles() {
423     DCHECK_NOT_NULL(canonical_handles_);
424     return std::move(canonical_handles_);
425   }
426 
427   // Copy the canonical handles over to the JSHeapBroker.
428   void CopyCanonicalHandlesForTesting(
429       std::unique_ptr<CanonicalHandlesMap> canonical_handles);
430 
431   Isolate* const isolate_;
432 #if V8_COMPRESS_POINTERS
433   const PtrComprCageBase cage_base_;
434 #endif  // V8_COMPRESS_POINTERS
435   Zone* const zone_;
436   base::Optional<NativeContextRef> target_native_context_;
437   RefsMap* refs_;
438   RootIndexMap root_index_map_;
439   ZoneUnorderedSet<Handle<JSObject>, Handle<JSObject>::hash,
440                    Handle<JSObject>::equal_to>
441       array_and_object_prototypes_;
442   BrokerMode mode_ = kDisabled;
443   bool const tracing_enabled_;
444   CodeKind const code_kind_;
445   std::unique_ptr<PersistentHandles> ph_;
446   LocalIsolate* local_isolate_ = nullptr;
447   std::unique_ptr<CanonicalHandlesMap> canonical_handles_;
448   unsigned trace_indentation_ = 0;
449   ZoneUnorderedMap<FeedbackSource, ProcessedFeedback const*,
450                    FeedbackSource::Hash, FeedbackSource::Equal>
451       feedback_;
452   ZoneUnorderedMap<PropertyAccessTarget, PropertyAccessInfo,
453                    PropertyAccessTarget::Hash, PropertyAccessTarget::Equal>
454       property_access_infos_;
455 
456   CompilationDependencies* dependencies_ = nullptr;
457 
458   // The MapUpdater mutex is used in recursive patterns; for example,
459   // ComputePropertyAccessInfo may call itself recursively. Thus we need to
460   // emulate a recursive mutex, which we do by checking if this heap broker
461   // instance already holds the mutex when a lock is requested. This field
462   // holds the locking depth, i.e. how many times the mutex has been
463   // recursively locked. Only the outermost locker actually locks underneath.
464   int map_updater_mutex_depth_ = 0;
465   // Likewise for boilerplate migrations.
466   int boilerplate_migration_mutex_depth_ = 0;
467 
468   static constexpr uint32_t kMinimalRefsBucketCount = 8;
469   STATIC_ASSERT(base::bits::IsPowerOfTwo(kMinimalRefsBucketCount));
470   static constexpr uint32_t kInitialRefsBucketCount = 1024;
471   STATIC_ASSERT(base::bits::IsPowerOfTwo(kInitialRefsBucketCount));
472 };
473 
474 class V8_NODISCARD TraceScope {
475  public:
TraceScope(JSHeapBroker * broker,const char * label)476   TraceScope(JSHeapBroker* broker, const char* label)
477       : TraceScope(broker, static_cast<void*>(broker), label) {}
478 
TraceScope(JSHeapBroker * broker,ObjectData * data,const char * label)479   TraceScope(JSHeapBroker* broker, ObjectData* data, const char* label)
480       : TraceScope(broker, static_cast<void*>(data), label) {}
481 
TraceScope(JSHeapBroker * broker,void * subject,const char * label)482   TraceScope(JSHeapBroker* broker, void* subject, const char* label)
483       : broker_(broker) {
484     TRACE_BROKER(broker_, "Running " << label << " on " << subject);
485     broker_->IncrementTracingIndentation();
486   }
487 
~TraceScope()488   ~TraceScope() { broker_->DecrementTracingIndentation(); }
489 
490  private:
491   JSHeapBroker* const broker_;
492 };
493 
494 // Scope that unparks the LocalHeap, if:
495 //   a) We have a JSHeapBroker,
496 //   b) Said JSHeapBroker has a LocalIsolate and thus a LocalHeap,
497 //   c) Said LocalHeap has been parked and
498 //   d) The given condition evaluates to true.
499 // Used, for example, when printing the graph with --trace-turbo with a
500 // previously parked LocalHeap.
501 class V8_NODISCARD UnparkedScopeIfNeeded {
502  public:
503   explicit UnparkedScopeIfNeeded(JSHeapBroker* broker,
504                                  bool extra_condition = true) {
505     if (broker != nullptr && extra_condition) {
506       LocalIsolate* local_isolate = broker->local_isolate();
507       if (local_isolate != nullptr && local_isolate->heap()->IsParked()) {
508         unparked_scope.emplace(local_isolate->heap());
509       }
510     }
511   }
512 
513  private:
514   base::Optional<UnparkedScope> unparked_scope;
515 };
516 
517 template <class T,
518           typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
TryMakeRef(JSHeapBroker * broker,ObjectData * data)519 base::Optional<typename ref_traits<T>::ref_type> TryMakeRef(
520     JSHeapBroker* broker, ObjectData* data) {
521   if (data == nullptr) return {};
522   return {typename ref_traits<T>::ref_type(broker, data)};
523 }
524 
525 // Usage:
526 //
527 //  base::Optional<FooRef> ref = TryMakeRef(broker, o);
528 //  if (!ref.has_value()) return {};  // bailout
529 //
530 // or
531 //
532 //  FooRef ref = MakeRef(broker, o);
533 template <class T,
534           typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
535 base::Optional<typename ref_traits<T>::ref_type> TryMakeRef(
536     JSHeapBroker* broker, T object, GetOrCreateDataFlags flags = {}) {
537   ObjectData* data = broker->TryGetOrCreateData(object, flags);
538   if (data == nullptr) {
539     TRACE_BROKER_MISSING(broker, "ObjectData for " << Brief(object));
540   }
541   return TryMakeRef<T>(broker, data);
542 }
543 
544 template <class T,
545           typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
546 base::Optional<typename ref_traits<T>::ref_type> TryMakeRef(
547     JSHeapBroker* broker, Handle<T> object, GetOrCreateDataFlags flags = {}) {
548   ObjectData* data = broker->TryGetOrCreateData(object, flags);
549   if (data == nullptr) {
550     DCHECK_EQ(flags & kCrashOnError, 0);
551     TRACE_BROKER_MISSING(broker, "ObjectData for " << Brief(*object));
552   }
553   return TryMakeRef<T>(broker, data);
554 }
555 
556 template <class T,
557           typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
MakeRef(JSHeapBroker * broker,T object)558 typename ref_traits<T>::ref_type MakeRef(JSHeapBroker* broker, T object) {
559   return TryMakeRef(broker, object, kCrashOnError).value();
560 }
561 
562 template <class T,
563           typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
MakeRef(JSHeapBroker * broker,Handle<T> object)564 typename ref_traits<T>::ref_type MakeRef(JSHeapBroker* broker,
565                                          Handle<T> object) {
566   return TryMakeRef(broker, object, kCrashOnError).value();
567 }
568 
569 template <class T,
570           typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
MakeRefAssumeMemoryFence(JSHeapBroker * broker,T object)571 typename ref_traits<T>::ref_type MakeRefAssumeMemoryFence(JSHeapBroker* broker,
572                                                           T object) {
573   return TryMakeRef(broker, object, kAssumeMemoryFence | kCrashOnError).value();
574 }
575 
576 template <class T,
577           typename = std::enable_if_t<std::is_convertible<T*, Object*>::value>>
MakeRefAssumeMemoryFence(JSHeapBroker * broker,Handle<T> object)578 typename ref_traits<T>::ref_type MakeRefAssumeMemoryFence(JSHeapBroker* broker,
579                                                           Handle<T> object) {
580   return TryMakeRef(broker, object, kAssumeMemoryFence | kCrashOnError).value();
581 }
582 
583 }  // namespace compiler
584 }  // namespace internal
585 }  // namespace v8
586 
587 #endif  // V8_COMPILER_JS_HEAP_BROKER_H_
588