MaybeRooted.h (3679B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * Template types for use in generic code: to use Rooted/Handle/MutableHandle in 9 * cases where GC may occur, or to use mock versions of those types that perform 10 * no rooting or root list manipulation when GC cannot occur. 11 */ 12 13 #ifndef gc_MaybeRooted_h 14 #define gc_MaybeRooted_h 15 16 #include "mozilla/Attributes.h" // MOZ_IMPLICIT, MOZ_RAII 17 18 #include <type_traits> // std::true_type 19 20 #include "gc/GCEnum.h" // js::AllowGC, js::CanGC, js::NoGC 21 #include "js/ComparisonOperators.h" // JS::detail::DefineComparisonOps 22 #include "js/RootingAPI.h" // js::{Rooted,MutableHandle}Base, JS::SafelyInitialized, DECLARE_POINTER_{CONSTREF,ASSIGN}_OPS, DECLARE_NONPOINTER_{,MUTABLE_}ACCESSOR_METHODS, JS::Rooted, JS::{,Mutable}Handle 23 24 namespace js { 25 26 /** 27 * Interface substitute for Rooted<T> which does not root the variable's 28 * memory. 29 */ 30 template <typename T> 31 class MOZ_RAII FakeRooted : public RootedOperations<T, FakeRooted<T>> { 32 public: 33 using ElementType = T; 34 35 explicit FakeRooted(JSContext* cx) 36 : ptr(JS::SafelyInitialized<T>::create()) {} 37 38 FakeRooted(JSContext* cx, const T& initial) : ptr(initial) {} 39 40 FakeRooted(const FakeRooted&) = delete; 41 42 DECLARE_POINTER_CONSTREF_OPS(T); 43 DECLARE_POINTER_ASSIGN_OPS(FakeRooted, T); 44 DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); 45 DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr); 46 47 operator JS::Handle<T>() { return JS::Handle<T>::fromMarkedLocation(&ptr); } 48 49 private: 50 T ptr; 51 52 void set(const T& value) { ptr = value; } 53 }; 54 55 } // namespace js 56 57 namespace JS::detail { 58 template <typename T> 59 struct DefineComparisonOps<js::FakeRooted<T>> : std::true_type { 60 static const T& get(const js::FakeRooted<T>& v) { return v.get(); } 61 }; 62 } // namespace JS::detail 63 64 namespace js { 65 66 /** 67 * Interface substitute for MutableHandle<T> which is not required to point to 68 * rooted memory. 69 */ 70 template <typename T> 71 class FakeMutableHandle 72 : public js::MutableHandleOperations<T, FakeMutableHandle<T>> { 73 public: 74 using ElementType = T; 75 76 MOZ_IMPLICIT FakeMutableHandle(T* t) : ptr(t) {} 77 78 MOZ_IMPLICIT FakeMutableHandle(FakeRooted<T>* root) : ptr(root->address()) {} 79 80 void set(const T& v) { *ptr = v; } 81 82 DECLARE_POINTER_CONSTREF_OPS(T); 83 DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); 84 DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr); 85 86 private: 87 FakeMutableHandle() : ptr(nullptr) {} 88 DELETE_ASSIGNMENT_OPS(FakeMutableHandle, T); 89 90 T* ptr; 91 }; 92 93 } // namespace js 94 95 namespace JS::detail { 96 template <typename T> 97 struct DefineComparisonOps<js::FakeMutableHandle<T>> : std::true_type { 98 static const T& get(const js::FakeMutableHandle<T>& v) { return v.get(); } 99 }; 100 } // namespace JS::detail 101 102 namespace js { 103 104 /** 105 * Types for a variable that either should or shouldn't be rooted, depending on 106 * the template parameter allowGC. Used for implementing functions that can 107 * operate on either rooted or unrooted data. 108 */ 109 110 template <typename T, AllowGC allowGC> 111 class MaybeRooted; 112 113 template <typename T> 114 class MaybeRooted<T, CanGC> { 115 public: 116 using HandleType = JS::Handle<T>; 117 using RootType = JS::Rooted<T>; 118 using MutableHandleType = JS::MutableHandle<T>; 119 }; 120 121 template <typename T> 122 class MaybeRooted<T, NoGC> { 123 public: 124 using HandleType = const T&; 125 using RootType = FakeRooted<T>; 126 using MutableHandleType = FakeMutableHandle<T>; 127 }; 128 129 } // namespace js 130 131 #endif // gc_MaybeRooted_h