Bug 1486596 - Add WeakRef support to mozilla::jni r=jchen
authorJames Willcox <snorp@snorp.net>
Wed, 29 Aug 2018 13:10:24 -0500
changeset 495216 fabcbe61060edda6f51bd7f790be044542505b6d
parent 495215 4526e08d44775dd3c32ce27c16d96e4b995eea60
child 495217 e7ddac13c48fd31edaaaf69288c6e8151bd91738
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjchen
bugs1486596
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1486596 - Add WeakRef support to mozilla::jni r=jchen
widget/android/jni/Refs.h
--- a/widget/android/jni/Refs.h
+++ b/widget/android/jni/Refs.h
@@ -16,16 +16,18 @@ namespace jni {
 // Wrapped object reference (e.g. jobject, jclass, etc...)
 template<class Cls, typename JNIType> class Ref;
 // Represents a calling context for JNI methods.
 template<class Cls, typename JNIType> class Context;
 // Wrapped local reference that inherits from Ref.
 template<class Cls> class LocalRef;
 // Wrapped global reference that inherits from Ref.
 template<class Cls> class GlobalRef;
+// Wrapped weak reference that inherits from Ref.
+template<class Cls> class WeakRef;
 // Wrapped dangling reference that's owned by someone else.
 template<class Cls> class DependentRef;
 
 
 // Class to hold the native types of a method's arguments.
 // For example, if a method has signature (ILjava/lang/String;)V,
 // its arguments class would be jni::Args<int32_t, jni::String::Param>
 template<typename...>
@@ -307,16 +309,17 @@ protected:
     JNIEnv* Env() const { return mCtx.Env(); }
     Type Instance() const { return mCtx.Get(); }
 
 public:
     using Ref = jni::Ref<Cls, Type>;
     using Context = jni::Context<Cls, Type>;
     using LocalRef = jni::LocalRef<Cls>;
     using GlobalRef = jni::GlobalRef<Cls>;
+    using WeakRef = jni::WeakRef<Cls>;
     using Param = const Ref&;
 
     static const CallingThread callingThread = CallingThread::ANY;
     static const char name[];
 
     explicit ObjectBase(const Context& ctx) : mCtx(ctx) {}
 
     Cls* operator->()
@@ -666,16 +669,119 @@ public:
 
     GlobalRef<Cls>& operator=(decltype(nullptr)) &
     {
         GlobalRef<Cls> newRef(nullptr);
         return swap(newRef);
     }
 };
 
+template<class Cls>
+class WeakRef : public Ref<Cls, jweak>
+{
+    using Ref = Ref<Cls, jweak>;
+    using JNIType = typename Ref::JNIType;
+
+    static JNIType NewWeakRef(JNIEnv* env, JNIType instance)
+    {
+        return JNIType(instance ? env->NewWeakGlobalRef(instance) : nullptr);
+    }
+
+    WeakRef& swap(WeakRef& other)
+    {
+        auto instance = other.mInstance;
+        other.mInstance = Ref::mInstance;
+        Ref::mInstance = instance;
+        return *this;
+    }
+
+public:
+    WeakRef()
+        : Ref(nullptr)
+    {}
+
+    // Copy constructor
+    WeakRef(const WeakRef& ref)
+        : Ref(NewWeakRef(GetEnvForThread(), ref.mInstance))
+    {}
+
+    // Move constructor
+    WeakRef(WeakRef&& ref)
+        : Ref(ref.mInstance)
+    {
+        ref.mInstance = nullptr;
+    }
+
+    MOZ_IMPLICIT WeakRef(const Ref& ref)
+        : Ref(NewWeakRef(GetEnvForThread(), ref.Get()))
+    {}
+
+    WeakRef(JNIEnv* env, const Ref& ref)
+        : Ref(NewWeakRef(env, ref.Get()))
+    {}
+
+    MOZ_IMPLICIT WeakRef(const LocalRef<Cls>& ref)
+        : Ref(NewWeakRef(ref.Env(), ref.Get()))
+    {}
+
+    // Implicitly converts nullptr to WeakRef.
+    MOZ_IMPLICIT WeakRef(decltype(nullptr))
+        : Ref(nullptr)
+    {}
+
+    ~WeakRef()
+    {
+        if (Ref::mInstance) {
+            Clear(GetEnvForThread());
+        }
+    }
+
+    // Get the raw JNI reference that can be used as a return value.
+    // Returns the same JNI type (jobject, jstring, etc.) as the underlying Ref.
+    typename Ref::JNIType Forget()
+    {
+        const auto obj = Ref::Get();
+        Ref::mInstance = nullptr;
+        return obj;
+    }
+
+    void Clear(JNIEnv* env)
+    {
+        if (Ref::mInstance) {
+            env->DeleteWeakGlobalRef(Ref::mInstance);
+            Ref::mInstance = nullptr;
+        }
+    }
+
+    WeakRef<Cls>& operator=(WeakRef<Cls> ref) &
+    {
+        return swap(ref);
+    }
+
+    WeakRef<Cls>& operator=(const Ref& ref) &
+    {
+        WeakRef<Cls> newRef(ref);
+        return swap(newRef);
+    }
+
+    WeakRef<Cls>& operator=(const LocalRef<Cls>& ref) &
+    {
+        WeakRef<Cls> newRef(ref);
+        return swap(newRef);
+    }
+
+    WeakRef<Cls>& operator=(decltype(nullptr)) &
+    {
+        WeakRef<Cls> newRef(nullptr);
+        return swap(newRef);
+    }
+
+    void operator->() const = delete;
+    void operator*() const = delete;
+};
 
 template<class Cls>
 class DependentRef : public Cls::Ref
 {
     using Ref = typename Cls::Ref;
 
 public:
     explicit DependentRef(typename Ref::JNIType instance)