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