mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	Actually, `NativeWeakPtr::Detach` may not release JNI ojbect immediately because it depends on JNI object's `OnWeakNonIntrusiveDetach`i implementation. `SessionAccessibility`'s `OnWeakNonIntrusiveDetach` implementation uses the runnable to run on Android UI thread then disposer runs on main thread, so if Detach is finished, JNI object isn't detached yet. If calling `NativeWeakPtrHolder::Attach` immediately with same/recycled Java object after `NettiveWeakPtr::Detach`, it is possible to run disposer for JNI object by `OnWeakNonIntrusiveDetach` after Attach is finished. So it may release newer attached object unfortunately. So I would like to add a way to waiting for detach JNI object using `MozPromise`. Also, `MozPromise.h` includes `Natives.h` header (for `GeckoResult` support). So I cannot modify inline method to use `MozPromise` due to recursive. So I split implementation with `NativesInlines.h` as workaround. Differential Revision: https://phabricator.services.mozilla.com/D175335
		
			
				
	
	
		
			1540 lines
		
	
	
	
		
			52 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1540 lines
		
	
	
	
		
			52 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#ifndef mozilla_jni_Natives_h__
 | 
						|
#define mozilla_jni_Natives_h__
 | 
						|
 | 
						|
#include <jni.h>
 | 
						|
#include <tuple>
 | 
						|
#include <type_traits>
 | 
						|
#include <utility>
 | 
						|
 | 
						|
#include "mozilla/RefPtr.h"
 | 
						|
#include "mozilla/RWLock.h"
 | 
						|
#include "mozilla/UniquePtr.h"
 | 
						|
#include "mozilla/Unused.h"
 | 
						|
#include "mozilla/WeakPtr.h"
 | 
						|
#include "mozilla/jni/Accessors.h"
 | 
						|
#include "mozilla/jni/Refs.h"
 | 
						|
#include "mozilla/jni/Types.h"
 | 
						|
#include "mozilla/jni/Utils.h"
 | 
						|
#include "nsThreadUtils.h"
 | 
						|
 | 
						|
#if defined(_MSC_VER)  // MSVC
 | 
						|
#  define FUNCTION_SIGNATURE __FUNCSIG__
 | 
						|
#elif defined(__GNUC__)  // GCC, Clang
 | 
						|
#  define FUNCTION_SIGNATURE __PRETTY_FUNCTION__
 | 
						|
#endif
 | 
						|
 | 
						|
struct NativeException {
 | 
						|
  const char* str;
 | 
						|
};
 | 
						|
 | 
						|
template <class T>
 | 
						|
static NativeException NullHandle() {
 | 
						|
  return {FUNCTION_SIGNATURE};
 | 
						|
}
 | 
						|
 | 
						|
template <class T>
 | 
						|
static NativeException NullWeakPtr() {
 | 
						|
  return {FUNCTION_SIGNATURE};
 | 
						|
}
 | 
						|
 | 
						|
namespace mozilla {
 | 
						|
 | 
						|
template <typename ResolveValueT, typename RejectValueT, bool IsExclusive>
 | 
						|
class MozPromise;
 | 
						|
 | 
						|
namespace jni {
 | 
						|
 | 
						|
/**
 | 
						|
 * C++ classes implementing instance (non-static) native methods can choose
 | 
						|
 * from one of two ownership models, when associating a C++ object with a Java
 | 
						|
 * instance.
 | 
						|
 *
 | 
						|
 * * If the C++ class inherits from mozilla::SupportsWeakPtr, weak pointers
 | 
						|
 *   will be used. The Java instance will store and own the pointer to a
 | 
						|
 *   WeakPtr object. The C++ class itself is otherwise not owned or directly
 | 
						|
 *   referenced. Note that mozilla::SupportsWeakPtr only supports being used on
 | 
						|
 *   a single thread. To attach a Java instance to a C++ instance, pass in a
 | 
						|
 *   mozilla::SupportsWeakPtr pointer to the C++ class (i.e. MyClass*).
 | 
						|
 *
 | 
						|
 *   class MyClass : public SupportsWeakPtr
 | 
						|
 *                 , public MyJavaClass::Natives<MyClass>
 | 
						|
 *   {
 | 
						|
 *       // ...
 | 
						|
 *
 | 
						|
 *   public:
 | 
						|
 *       using MyJavaClass::Natives<MyClass>::DisposeNative;
 | 
						|
 *
 | 
						|
 *       void AttachTo(const MyJavaClass::LocalRef& instance)
 | 
						|
 *       {
 | 
						|
 *           MyJavaClass::Natives<MyClass>::AttachNative(
 | 
						|
 *                   instance, static_cast<SupportsWeakPtr*>(this));
 | 
						|
 *
 | 
						|
 *           // "instance" does NOT own "this", so the C++ object
 | 
						|
 *           // lifetime is separate from the Java object lifetime.
 | 
						|
 *       }
 | 
						|
 *   };
 | 
						|
 *
 | 
						|
 * * If the C++ class contains public members AddRef() and Release(), the Java
 | 
						|
 *   instance will store and own the pointer to a RefPtr object, which holds a
 | 
						|
 *   strong reference on the C++ instance. Normal ref-counting considerations
 | 
						|
 *   apply in this case; for example, disposing may cause the C++ instance to
 | 
						|
 *   be deleted and the destructor to be run on the current thread, which may
 | 
						|
 *   not be desirable. To attach a Java instance to a C++ instance, pass in a
 | 
						|
 *   pointer to the C++ class (i.e. MyClass*).
 | 
						|
 *
 | 
						|
 *   class MyClass : public RefCounted<MyClass>
 | 
						|
 *                 , public MyJavaClass::Natives<MyClass>
 | 
						|
 *   {
 | 
						|
 *       // ...
 | 
						|
 *
 | 
						|
 *   public:
 | 
						|
 *       using MyJavaClass::Natives<MyClass>::DisposeNative;
 | 
						|
 *
 | 
						|
 *       void AttachTo(const MyJavaClass::LocalRef& instance)
 | 
						|
 *       {
 | 
						|
 *           MyJavaClass::Natives<MyClass>::AttachNative(instance, this);
 | 
						|
 *
 | 
						|
 *           // "instance" owns "this" through the RefPtr, so the C++ object
 | 
						|
 *           // may be destroyed as soon as instance.disposeNative() is called.
 | 
						|
 *       }
 | 
						|
 *   };
 | 
						|
 *
 | 
						|
 * * In other cases, the Java instance will store and own a pointer to the C++
 | 
						|
 *   object itself. This pointer must not be stored or deleted elsewhere. To
 | 
						|
 *   attach a Java instance to a C++ instance, pass in a reference to a
 | 
						|
 *   UniquePtr of the C++ class (i.e. UniquePtr<MyClass>).
 | 
						|
 *
 | 
						|
 *   class MyClass : public MyJavaClass::Natives<MyClass>
 | 
						|
 *   {
 | 
						|
 *       // ...
 | 
						|
 *
 | 
						|
 *   public:
 | 
						|
 *       using MyJavaClass::Natives<MyClass>::DisposeNative;
 | 
						|
 *
 | 
						|
 *       static void AttachTo(const MyJavaClass::LocalRef& instance)
 | 
						|
 *       {
 | 
						|
 *           MyJavaClass::Natives<MyClass>::AttachNative(
 | 
						|
 *                   instance, mozilla::MakeUnique<MyClass>());
 | 
						|
 *
 | 
						|
 *           // "instance" owns the newly created C++ object, so the C++
 | 
						|
 *           // object is destroyed as soon as instance.disposeNative() is
 | 
						|
 *           // called.
 | 
						|
 *       }
 | 
						|
 *   };
 | 
						|
 */
 | 
						|
 | 
						|
namespace detail {
 | 
						|
 | 
						|
/**
 | 
						|
 * Type trait that determines whether a given class has a member named
 | 
						|
 * T::OnWeakNonIntrusiveDetach.
 | 
						|
 *
 | 
						|
 * Example usage:
 | 
						|
 * class Foo {};
 | 
						|
 * class Bar {
 | 
						|
 *  public:
 | 
						|
 *   void OnWeakNonIntrusiveDetach(already_AddRefed<nsIRunnable> aRunnable);
 | 
						|
 * };
 | 
						|
 *
 | 
						|
 * constexpr bool foo = HasWeakNonIntrusiveDetach<Foo>::value; // Expect false
 | 
						|
 * constexpr bool bar = HasWeakNonIntrusiveDetach<Bar>::value; // Expect true
 | 
						|
 */
 | 
						|
template <typename, typename = std::void_t<>>
 | 
						|
struct HasWeakNonIntrusiveDetach : std::false_type {};
 | 
						|
 | 
						|
template <typename T>
 | 
						|
struct HasWeakNonIntrusiveDetach<
 | 
						|
    T, std::void_t<decltype(std::declval<T>().OnWeakNonIntrusiveDetach(
 | 
						|
           std::declval<already_AddRefed<nsIRunnable>>()))>> : std::true_type {
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Type trait that determines whether a given class is refcounted, ie. it has
 | 
						|
 * both T::AddRef and T::Release methods.
 | 
						|
 *
 | 
						|
 * Example usage:
 | 
						|
 * class Foo {};
 | 
						|
 * class Bar {
 | 
						|
 *  public:
 | 
						|
 *   void AddRef();
 | 
						|
 *   void Release();
 | 
						|
 * };
 | 
						|
 *
 | 
						|
 * constexpr bool foo = IsRefCounted<Foo>::value; // Expect false
 | 
						|
 * constexpr bool bar = IsRefCounted<Bar>::value; // Expect true
 | 
						|
 */
 | 
						|
template <typename, typename = std::void_t<>>
 | 
						|
struct IsRefCounted : std::false_type {};
 | 
						|
 | 
						|
template <typename T>
 | 
						|
struct IsRefCounted<T, std::void_t<decltype(std::declval<T>().AddRef(),
 | 
						|
                                            std::declval<T>().Release())>>
 | 
						|
    : std::true_type {};
 | 
						|
 | 
						|
/**
 | 
						|
 * This enum is used for classifying the type of pointer that is stored
 | 
						|
 * within a NativeWeakPtr. This classification is different from the one used
 | 
						|
 * for normal native pointers.
 | 
						|
 */
 | 
						|
enum class NativePtrInternalType : size_t {
 | 
						|
  OWNING = 1,
 | 
						|
  WEAK = 2,
 | 
						|
  REFPTR = 3,
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * NativePtrInternalPicker uses some C++ SFINAE template-fu to figure out
 | 
						|
 * what type of pointer the class specified by Impl needs to be.
 | 
						|
 *
 | 
						|
 * It does this by supplying multiple overloads of a method named Test.
 | 
						|
 * Various overloads are enabled or disabled depending on whether or not Impl
 | 
						|
 * can possibly support them.
 | 
						|
 *
 | 
						|
 * Each overload "returns" a reference to an array whose size corresponds to the
 | 
						|
 * value of each enum in NativePtrInternalType. That size is then converted back
 | 
						|
 * to the enum value, yielding the right type.
 | 
						|
 */
 | 
						|
template <class Impl>
 | 
						|
class NativePtrInternalPicker {
 | 
						|
  // Enable if Impl derives from SupportsWeakPtr, yielding type WEAK
 | 
						|
  template <class I>
 | 
						|
  static std::enable_if_t<
 | 
						|
      std::is_base_of<SupportsWeakPtr, I>::value,
 | 
						|
      char (&)[static_cast<size_t>(NativePtrInternalType::WEAK)]>
 | 
						|
  Test(char);
 | 
						|
 | 
						|
  // Enable if Impl implements AddRef and Release, yielding type REFPTR
 | 
						|
  template <class I, typename = decltype(&I::AddRef, &I::Release)>
 | 
						|
  static char (&Test(int))[static_cast<size_t>(NativePtrInternalType::REFPTR)];
 | 
						|
 | 
						|
  // This overload uses '...' as its param to make its arguments less specific;
 | 
						|
  // the compiler prefers more-specific overloads to less-specific ones.
 | 
						|
  // OWNING is the fallback type.
 | 
						|
  template <class>
 | 
						|
  static char (&Test(...))[static_cast<size_t>(NativePtrInternalType::OWNING)];
 | 
						|
 | 
						|
 public:
 | 
						|
  // Given a hypothetical function call Test<Impl>, convert the size of its
 | 
						|
  // resulting array back into a NativePtrInternalType enum value.
 | 
						|
  static const NativePtrInternalType value = static_cast<NativePtrInternalType>(
 | 
						|
      sizeof(Test<Impl>('\0')) / sizeof(char));
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * This enum is used for classifying the type of pointer that is stored in a
 | 
						|
 * JNIObject's handle.
 | 
						|
 *
 | 
						|
 * We have two different weak pointer types:
 | 
						|
 *   * WEAK_INTRUSIVE is a pointer to a class that derives from
 | 
						|
 *     mozilla::SupportsWeakPtr.
 | 
						|
 *   * WEAK_NON_INTRUSIVE is a pointer to a class that does not have any
 | 
						|
 *     internal support for weak pointers, but does supply a
 | 
						|
 *     OnWeakNonIntrusiveDetach method.
 | 
						|
 */
 | 
						|
enum class NativePtrType : size_t {
 | 
						|
  OWNING = 1,
 | 
						|
  WEAK_INTRUSIVE = 2,
 | 
						|
  WEAK_NON_INTRUSIVE = 3,
 | 
						|
  REFPTR = 4,
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * NativePtrPicker uses some C++ SFINAE template-fu to figure out what type of
 | 
						|
 * pointer the class specified by Impl needs to be.
 | 
						|
 *
 | 
						|
 * It does this by supplying multiple overloads of a method named Test.
 | 
						|
 * Various overloads are enabled or disabled depending on whether or not Impl
 | 
						|
 * can possibly support them.
 | 
						|
 *
 | 
						|
 * Each overload "returns" a reference to an array whose size corresponds to the
 | 
						|
 * value of each enum in NativePtrInternalType. That size is then converted back
 | 
						|
 * to the enum value, yielding the right type.
 | 
						|
 */
 | 
						|
template <class Impl>
 | 
						|
class NativePtrPicker {
 | 
						|
  // Just shorthand for each overload's return type
 | 
						|
  template <NativePtrType PtrType>
 | 
						|
  using ResultTypeT = char (&)[static_cast<size_t>(PtrType)];
 | 
						|
 | 
						|
  // Enable if Impl derives from SupportsWeakPtr, yielding type WEAK_INTRUSIVE
 | 
						|
  template <typename I>
 | 
						|
  static auto Test(void*)
 | 
						|
      -> std::enable_if_t<std::is_base_of<SupportsWeakPtr, I>::value,
 | 
						|
                          ResultTypeT<NativePtrType::WEAK_INTRUSIVE>>;
 | 
						|
 | 
						|
  // Enable if Impl implements OnWeakNonIntrusiveDetach, yielding type
 | 
						|
  // WEAK_NON_INTRUSIVE
 | 
						|
  template <typename I>
 | 
						|
  static auto Test(void*)
 | 
						|
      -> std::enable_if_t<HasWeakNonIntrusiveDetach<I>::value,
 | 
						|
                          ResultTypeT<NativePtrType::WEAK_NON_INTRUSIVE>>;
 | 
						|
 | 
						|
  // We want the WEAK_NON_INTRUSIVE overload to take precedence over this one,
 | 
						|
  // so we only enable this overload if Impl is refcounted AND it does not
 | 
						|
  // implement OnWeakNonIntrusiveDetach. Yields type REFPTR.
 | 
						|
  template <typename I>
 | 
						|
  static auto Test(void*) -> std::enable_if_t<
 | 
						|
      std::conjunction_v<IsRefCounted<I>,
 | 
						|
                         std::negation<HasWeakNonIntrusiveDetach<I>>>,
 | 
						|
      ResultTypeT<NativePtrType::REFPTR>>;
 | 
						|
 | 
						|
  // This overload uses '...' as its param to make its arguments less specific;
 | 
						|
  // the compiler prefers more-specific overloads to less-specific ones.
 | 
						|
  // OWNING is the fallback type.
 | 
						|
  template <typename>
 | 
						|
  static char (&Test(...))[static_cast<size_t>(NativePtrType::OWNING)];
 | 
						|
 | 
						|
 public:
 | 
						|
  // Given a hypothetical function call Test<Impl>, convert the size of its
 | 
						|
  // resulting array back into a NativePtrType enum value.
 | 
						|
  static const NativePtrType value =
 | 
						|
      static_cast<NativePtrType>(sizeof(Test<Impl>(nullptr)));
 | 
						|
};
 | 
						|
 | 
						|
template <class Impl>
 | 
						|
inline uintptr_t CheckNativeHandle(JNIEnv* env, uintptr_t handle) {
 | 
						|
  if (!handle) {
 | 
						|
    if (!env->ExceptionCheck()) {
 | 
						|
      ThrowException(env, "java/lang/NullPointerException",
 | 
						|
                     NullHandle<Impl>().str);
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
  return handle;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * This struct is used to describe various traits of a native pointer of type
 | 
						|
 * Impl that will be attached to a JNIObject.
 | 
						|
 *
 | 
						|
 * See the definition of the NativePtrType::OWNING specialization for comments
 | 
						|
 * describing the required fields.
 | 
						|
 */
 | 
						|
template <class Impl, NativePtrType Type = NativePtrPicker<Impl>::value>
 | 
						|
struct NativePtrTraits;
 | 
						|
 | 
						|
template <class Impl>
 | 
						|
struct NativePtrTraits<Impl, /* Type = */ NativePtrType::OWNING> {
 | 
						|
  using AccessorType =
 | 
						|
      Impl*;  // Pointer-like type returned by Access() (an actual pointer in
 | 
						|
              // this case, but this is not strictly necessary)
 | 
						|
  using HandleType = Impl*;  // Type of the pointer stored in JNIObject.mHandle
 | 
						|
  using RefType = Impl*;     // Type of the pointer returned by Get()
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns a RefType to the native implementation belonging to
 | 
						|
   * the given Java object.
 | 
						|
   */
 | 
						|
  static RefType Get(JNIEnv* env, jobject instance) {
 | 
						|
    static_assert(
 | 
						|
        std::is_same<HandleType, RefType>::value,
 | 
						|
        "HandleType and RefType must be identical for owning pointers");
 | 
						|
    return reinterpret_cast<HandleType>(
 | 
						|
        CheckNativeHandle<Impl>(env, GetNativeHandle(env, instance)));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns a RefType to the native implementation belonging to
 | 
						|
   * the given Java object.
 | 
						|
   */
 | 
						|
  template <class LocalRef>
 | 
						|
  static RefType Get(const LocalRef& instance) {
 | 
						|
    return Get(instance.Env(), instance.Get());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Given a RefType, returns the pointer-like AccessorType used for
 | 
						|
   * manipulating the native object.
 | 
						|
   */
 | 
						|
  static AccessorType Access(RefType aImpl, JNIEnv* aEnv = nullptr) {
 | 
						|
    static_assert(
 | 
						|
        std::is_same<AccessorType, RefType>::value,
 | 
						|
        "AccessorType and RefType must be identical for owning pointers");
 | 
						|
    return aImpl;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Set the JNIObject's handle to the provided pointer, clearing any previous
 | 
						|
   * handle if necessary.
 | 
						|
   */
 | 
						|
  template <class LocalRef>
 | 
						|
  static void Set(const LocalRef& instance, UniquePtr<Impl>&& ptr) {
 | 
						|
    Clear(instance);
 | 
						|
    SetNativeHandle(instance.Env(), instance.Get(),
 | 
						|
                    reinterpret_cast<uintptr_t>(ptr.release()));
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Clear the JNIObject's handle.
 | 
						|
   */
 | 
						|
  template <class LocalRef>
 | 
						|
  static void Clear(const LocalRef& instance) {
 | 
						|
    UniquePtr<Impl> ptr(reinterpret_cast<RefType>(
 | 
						|
        GetNativeHandle(instance.Env(), instance.Get())));
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
 | 
						|
    if (ptr) {
 | 
						|
      SetNativeHandle(instance.Env(), instance.Get(), 0);
 | 
						|
      MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
template <class Impl>
 | 
						|
struct NativePtrTraits<Impl, /* Type = */ NativePtrType::WEAK_INTRUSIVE> {
 | 
						|
  using AccessorType = Impl*;
 | 
						|
  using HandleType = WeakPtr<Impl>*;
 | 
						|
  using RefType = WeakPtr<Impl>;
 | 
						|
 | 
						|
  static RefType Get(JNIEnv* env, jobject instance) {
 | 
						|
    const auto ptr = reinterpret_cast<HandleType>(
 | 
						|
        CheckNativeHandle<Impl>(env, GetNativeHandle(env, instance)));
 | 
						|
    return *ptr;
 | 
						|
  }
 | 
						|
 | 
						|
  template <class LocalRef>
 | 
						|
  static RefType Get(const LocalRef& instance) {
 | 
						|
    return Get(instance.Env(), instance.Get());
 | 
						|
  }
 | 
						|
 | 
						|
  static AccessorType Access(RefType aPtr, JNIEnv* aEnv = nullptr) {
 | 
						|
    AccessorType const impl = *aPtr;
 | 
						|
    if (!impl) {
 | 
						|
      JNIEnv* env = aEnv ? aEnv : mozilla::jni::GetEnvForThread();
 | 
						|
      ThrowException(env, "java/lang/NullPointerException",
 | 
						|
                     NullWeakPtr<Impl>().str);
 | 
						|
    }
 | 
						|
 | 
						|
    return impl;
 | 
						|
  }
 | 
						|
 | 
						|
  template <class LocalRef>
 | 
						|
  static void Set(const LocalRef& instance, Impl* ptr) {
 | 
						|
    // Create the new handle first before clearing any old handle, so the
 | 
						|
    // new handle is guaranteed to have different value than any old handle.
 | 
						|
    const uintptr_t handle =
 | 
						|
        reinterpret_cast<uintptr_t>(new WeakPtr<Impl>(ptr));
 | 
						|
    Clear(instance);
 | 
						|
    SetNativeHandle(instance.Env(), instance.Get(), handle);
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
  }
 | 
						|
 | 
						|
  template <class LocalRef>
 | 
						|
  static void Clear(const LocalRef& instance) {
 | 
						|
    const auto ptr = reinterpret_cast<HandleType>(
 | 
						|
        GetNativeHandle(instance.Env(), instance.Get()));
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
 | 
						|
    if (ptr) {
 | 
						|
      SetNativeHandle(instance.Env(), instance.Get(), 0);
 | 
						|
      MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
      delete ptr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
template <class Impl>
 | 
						|
struct NativePtrTraits<Impl, /* Type = */ NativePtrType::REFPTR> {
 | 
						|
  using AccessorType = Impl*;
 | 
						|
  using HandleType = RefPtr<Impl>*;
 | 
						|
  using RefType = Impl*;
 | 
						|
 | 
						|
  static RefType Get(JNIEnv* env, jobject instance) {
 | 
						|
    const auto ptr = reinterpret_cast<HandleType>(
 | 
						|
        CheckNativeHandle<Impl>(env, GetNativeHandle(env, instance)));
 | 
						|
    if (!ptr) {
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
    MOZ_ASSERT(*ptr);
 | 
						|
    return *ptr;
 | 
						|
  }
 | 
						|
 | 
						|
  template <class LocalRef>
 | 
						|
  static RefType Get(const LocalRef& instance) {
 | 
						|
    return Get(instance.Env(), instance.Get());
 | 
						|
  }
 | 
						|
 | 
						|
  static AccessorType Access(RefType aImpl, JNIEnv* aEnv = nullptr) {
 | 
						|
    static_assert(std::is_same<AccessorType, RefType>::value,
 | 
						|
                  "AccessorType and RefType must be identical for refpointers");
 | 
						|
    return aImpl;
 | 
						|
  }
 | 
						|
 | 
						|
  template <class LocalRef>
 | 
						|
  static void Set(const LocalRef& instance, RefType ptr) {
 | 
						|
    // Create the new handle first before clearing any old handle, so the
 | 
						|
    // new handle is guaranteed to have different value than any old handle.
 | 
						|
    const uintptr_t handle = reinterpret_cast<uintptr_t>(new RefPtr<Impl>(ptr));
 | 
						|
    Clear(instance);
 | 
						|
    SetNativeHandle(instance.Env(), instance.Get(), handle);
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
  }
 | 
						|
 | 
						|
  template <class LocalRef>
 | 
						|
  static void Clear(const LocalRef& instance) {
 | 
						|
    const auto ptr = reinterpret_cast<HandleType>(
 | 
						|
        GetNativeHandle(instance.Env(), instance.Get()));
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
 | 
						|
    if (ptr) {
 | 
						|
      SetNativeHandle(instance.Env(), instance.Get(), 0);
 | 
						|
      MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
      delete ptr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace detail
 | 
						|
 | 
						|
// Forward declarations
 | 
						|
template <typename NativeImpl>
 | 
						|
class NativeWeakPtr;
 | 
						|
template <typename NativeImpl>
 | 
						|
class NativeWeakPtrHolder;
 | 
						|
 | 
						|
namespace detail {
 | 
						|
 | 
						|
/**
 | 
						|
 * Given the class of a native implementation, as well as its
 | 
						|
 * NativePtrInternalType, resolve traits for that type that will be used by
 | 
						|
 * the NativeWeakPtrControlBlock.
 | 
						|
 *
 | 
						|
 * Note that we only implement specializations for OWNING and REFPTR types,
 | 
						|
 * as a WEAK_INTRUSIVE type should not be using NativeWeakPtr anyway. The build
 | 
						|
 * will fail if such an attempt is made.
 | 
						|
 *
 | 
						|
 * Traits need to implement two things:
 | 
						|
 * 1. A |Type| field that resolves to a pointer type to be stored in the
 | 
						|
 *    JNIObject's handle. It is assumed that setting a |Type| object to nullptr
 | 
						|
 *    is sufficient to delete the underlying object.
 | 
						|
 * 2. A static |AsRaw| method that converts a pointer of |Type| into a raw
 | 
						|
 *    pointer.
 | 
						|
 */
 | 
						|
template <
 | 
						|
    typename NativeImpl,
 | 
						|
    NativePtrInternalType PtrType =
 | 
						|
        ::mozilla::jni::detail::NativePtrInternalPicker<NativeImpl>::value>
 | 
						|
struct NativeWeakPtrControlBlockStorageTraits;
 | 
						|
 | 
						|
template <typename NativeImpl>
 | 
						|
struct NativeWeakPtrControlBlockStorageTraits<
 | 
						|
    NativeImpl, ::mozilla::jni::detail::NativePtrInternalType::OWNING> {
 | 
						|
  using Type = UniquePtr<NativeImpl>;
 | 
						|
 | 
						|
  static NativeImpl* AsRaw(const Type& aStorage) { return aStorage.get(); }
 | 
						|
};
 | 
						|
 | 
						|
template <typename NativeImpl>
 | 
						|
struct NativeWeakPtrControlBlockStorageTraits<
 | 
						|
    NativeImpl, ::mozilla::jni::detail::NativePtrInternalType::REFPTR> {
 | 
						|
  using Type = RefPtr<NativeImpl>;
 | 
						|
 | 
						|
  static NativeImpl* AsRaw(const Type& aStorage) { return aStorage.get(); }
 | 
						|
};
 | 
						|
 | 
						|
// Forward Declaration
 | 
						|
template <typename NativeImpl>
 | 
						|
class Accessor;
 | 
						|
 | 
						|
/**
 | 
						|
 * This class contains the shared data that is referenced by all NativeWeakPtr
 | 
						|
 * objects that reference the same object.
 | 
						|
 *
 | 
						|
 * It retains a WeakRef to the Java object that owns this native object.
 | 
						|
 * It uses a RWLock to control access to the native pointer itself.
 | 
						|
 * Read locks are used when accessing the pointer (even when calling non-const
 | 
						|
 * methods on the native object).
 | 
						|
 * A write lock is only used when it is time to destroy the native object and
 | 
						|
 * we need to clear the value of mNativeImpl.
 | 
						|
 */
 | 
						|
template <typename NativeImpl>
 | 
						|
class MOZ_HEAP_CLASS NativeWeakPtrControlBlock final {
 | 
						|
 public:
 | 
						|
  using StorageTraits = NativeWeakPtrControlBlockStorageTraits<NativeImpl>;
 | 
						|
  using StorageType = typename StorageTraits::Type;
 | 
						|
 | 
						|
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NativeWeakPtrControlBlock)
 | 
						|
 | 
						|
  NativeWeakPtrControlBlock(const NativeWeakPtrControlBlock&) = delete;
 | 
						|
  NativeWeakPtrControlBlock(NativeWeakPtrControlBlock&&) = delete;
 | 
						|
  NativeWeakPtrControlBlock& operator=(const NativeWeakPtrControlBlock&) =
 | 
						|
      delete;
 | 
						|
  NativeWeakPtrControlBlock& operator=(NativeWeakPtrControlBlock&&) = delete;
 | 
						|
 | 
						|
  // This is safe to call on any thread because mJavaOwner is immutable.
 | 
						|
  mozilla::jni::Object::WeakRef GetJavaOwner() const { return mJavaOwner; }
 | 
						|
 | 
						|
 private:
 | 
						|
  NativeWeakPtrControlBlock(::mozilla::jni::Object::Param aJavaOwner,
 | 
						|
                            StorageType&& aNativeImpl)
 | 
						|
      : mJavaOwner(aJavaOwner),
 | 
						|
        mLock("mozilla::jni::detail::NativeWeakPtrControlBlock"),
 | 
						|
        mNativeImpl(std::move(aNativeImpl)) {}
 | 
						|
 | 
						|
  ~NativeWeakPtrControlBlock() {
 | 
						|
    // Make sure that somebody, somewhere, has detached us before destroying.
 | 
						|
    MOZ_ASSERT(!(*this));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Clear the native pointer so that subsequent accesses to the native pointer
 | 
						|
   * via this control block are no longer available.
 | 
						|
   *
 | 
						|
   * We return the native pointer to the caller so that it may proceed with
 | 
						|
   * cleaning up its resources.
 | 
						|
   */
 | 
						|
  StorageType Clear() {
 | 
						|
    StorageType nativeImpl(nullptr);
 | 
						|
 | 
						|
    {  // Scope for lock
 | 
						|
      AutoWriteLock lock(mLock);
 | 
						|
      std::swap(mNativeImpl, nativeImpl);
 | 
						|
    }
 | 
						|
 | 
						|
    return nativeImpl;
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_PUSH_IGNORE_THREAD_SAFETY
 | 
						|
  void Lock() const { mLock.ReadLock(); }
 | 
						|
 | 
						|
  void Unlock() const { mLock.ReadUnlock(); }
 | 
						|
  MOZ_POP_THREAD_SAFETY
 | 
						|
 | 
						|
#if defined(DEBUG)
 | 
						|
  // This is kind of expensive, so we only support it in debug builds.
 | 
						|
  explicit operator bool() const {
 | 
						|
    AutoReadLock lock(mLock);
 | 
						|
    return !!mNativeImpl;
 | 
						|
  }
 | 
						|
#endif  // defined(DEBUG)
 | 
						|
 | 
						|
 private:
 | 
						|
  friend class Accessor<NativeImpl>;
 | 
						|
  friend class NativeWeakPtr<NativeImpl>;
 | 
						|
  friend class NativeWeakPtrHolder<NativeImpl>;
 | 
						|
 | 
						|
 private:
 | 
						|
  const mozilla::jni::Object::WeakRef mJavaOwner;
 | 
						|
  mutable RWLock mLock MOZ_UNANNOTATED;  // Protects mNativeImpl
 | 
						|
  StorageType mNativeImpl;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * If you want to temporarily access the object held by a NativeWeakPtr, you
 | 
						|
 * must obtain one of these Accessor objects from the pointer. Access must
 | 
						|
 * be done _exclusively_ using once of these objects!
 | 
						|
 */
 | 
						|
template <typename NativeImpl>
 | 
						|
class MOZ_STACK_CLASS Accessor final {
 | 
						|
 public:
 | 
						|
  ~Accessor() {
 | 
						|
    if (mCtlBlock) {
 | 
						|
      mCtlBlock->Unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Check whether the object is still valid before doing anything else
 | 
						|
  explicit operator bool() const { return mCtlBlock && mCtlBlock->mNativeImpl; }
 | 
						|
 | 
						|
  // Normal member access
 | 
						|
  NativeImpl* operator->() const {
 | 
						|
    return NativeWeakPtrControlBlockStorageTraits<NativeImpl>::AsRaw(
 | 
						|
        mCtlBlock->mNativeImpl);
 | 
						|
  }
 | 
						|
 | 
						|
  // This allows us to support calling a pointer to a member function
 | 
						|
  template <typename Member>
 | 
						|
  auto operator->*(Member aMember) const {
 | 
						|
    NativeImpl* impl =
 | 
						|
        NativeWeakPtrControlBlockStorageTraits<NativeImpl>::AsRaw(
 | 
						|
            mCtlBlock->mNativeImpl);
 | 
						|
    return [impl, member = aMember](auto&&... aArgs) {
 | 
						|
      return (impl->*member)(std::forward<decltype(aArgs)>(aArgs)...);
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  // Only available for NativeImpl types that actually use refcounting.
 | 
						|
  // The idea here is that it should be possible to obtain a strong ref from
 | 
						|
  // a NativeWeakPtr if and only if NativeImpl supports refcounting.
 | 
						|
  template <typename I = NativeImpl>
 | 
						|
  auto AsRefPtr() const -> std::enable_if_t<IsRefCounted<I>::value, RefPtr<I>> {
 | 
						|
    MOZ_ASSERT(I::HasThreadSafeRefCnt::value || NS_IsMainThread());
 | 
						|
    return mCtlBlock->mNativeImpl;
 | 
						|
  }
 | 
						|
 | 
						|
  Accessor(const Accessor&) = delete;
 | 
						|
  Accessor(Accessor&&) = delete;
 | 
						|
  Accessor& operator=(const Accessor&) = delete;
 | 
						|
  Accessor& operator=(Accessor&&) = delete;
 | 
						|
 | 
						|
 private:
 | 
						|
  explicit Accessor(
 | 
						|
      const RefPtr<detail::NativeWeakPtrControlBlock<NativeImpl>>& aCtlBlock)
 | 
						|
      : mCtlBlock(aCtlBlock) {
 | 
						|
    if (aCtlBlock) {
 | 
						|
      aCtlBlock->Lock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  friend class NativeWeakPtr<NativeImpl>;
 | 
						|
  friend class NativeWeakPtrHolder<NativeImpl>;
 | 
						|
 | 
						|
 private:
 | 
						|
  const RefPtr<NativeWeakPtrControlBlock<NativeImpl>> mCtlBlock;
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace detail
 | 
						|
 | 
						|
using DetachPromise = mozilla::MozPromise<bool, nsresult, true>;
 | 
						|
 | 
						|
/**
 | 
						|
 * This class implements support for thread-safe weak pointers to native objects
 | 
						|
 * that are owned by Java objects deriving from JNIObject.
 | 
						|
 *
 | 
						|
 * Any code that wants to access such a native object must have a copy of
 | 
						|
 * a NativeWeakPtr to that object.
 | 
						|
 */
 | 
						|
template <typename NativeImpl>
 | 
						|
class NativeWeakPtr {
 | 
						|
 public:
 | 
						|
  using Accessor = detail::Accessor<NativeImpl>;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Call this method to access the underlying object referenced by this
 | 
						|
   * NativeWeakPtr.
 | 
						|
   *
 | 
						|
   * Always check the returned Accessor object for availability before calling
 | 
						|
   * methods on it.
 | 
						|
   *
 | 
						|
   * For example, given:
 | 
						|
   *
 | 
						|
   * NativeWeakPtr<Foo> foo;
 | 
						|
   * auto accessor = foo.Access();
 | 
						|
   * if (accessor) {
 | 
						|
   *   // Okay, safe to work with
 | 
						|
   *   accessor->DoStuff();
 | 
						|
   * } else {
 | 
						|
   *   // The object's strong reference was cleared and is no longer available!
 | 
						|
   * }
 | 
						|
   */
 | 
						|
  Accessor Access() const { return Accessor(mCtlBlock); }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Detach the underlying object's strong reference from its owning Java object
 | 
						|
   * and clean it up.
 | 
						|
   */
 | 
						|
  RefPtr<DetachPromise> Detach();
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method does not indicate whether or not the weak pointer is still
 | 
						|
   * valid; it only indicates whether we're actually attached to one.
 | 
						|
   */
 | 
						|
  bool IsAttached() const { return !!mCtlBlock; }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Does this pointer reference the same object as the one referenced by the
 | 
						|
   * provided Accessor?
 | 
						|
   */
 | 
						|
  bool IsSame(const Accessor& aAccessor) const {
 | 
						|
    return mCtlBlock == aAccessor.mCtlBlock;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Does this pointer reference the same object as the one referenced by the
 | 
						|
   * provided Control Block?
 | 
						|
   */
 | 
						|
  bool IsSame(const RefPtr<detail::NativeWeakPtrControlBlock<NativeImpl>>&
 | 
						|
                  aOther) const {
 | 
						|
    return mCtlBlock == aOther;
 | 
						|
  }
 | 
						|
 | 
						|
  NativeWeakPtr() = default;
 | 
						|
  MOZ_IMPLICIT NativeWeakPtr(decltype(nullptr)) {}
 | 
						|
  NativeWeakPtr(const NativeWeakPtr& aOther) = default;
 | 
						|
  NativeWeakPtr(NativeWeakPtr&& aOther) = default;
 | 
						|
  NativeWeakPtr& operator=(const NativeWeakPtr& aOther) = default;
 | 
						|
  NativeWeakPtr& operator=(NativeWeakPtr&& aOther) = default;
 | 
						|
 | 
						|
  NativeWeakPtr& operator=(decltype(nullptr)) {
 | 
						|
    mCtlBlock = nullptr;
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
 | 
						|
 protected:
 | 
						|
  // Construction of initial NativeWeakPtr for aCtlBlock
 | 
						|
  explicit NativeWeakPtr(
 | 
						|
      already_AddRefed<detail::NativeWeakPtrControlBlock<NativeImpl>> aCtlBlock)
 | 
						|
      : mCtlBlock(aCtlBlock) {}
 | 
						|
 | 
						|
 private:
 | 
						|
  // Construction of subsequent NativeWeakPtrs for aCtlBlock
 | 
						|
  explicit NativeWeakPtr(
 | 
						|
      const RefPtr<detail::NativeWeakPtrControlBlock<NativeImpl>>& aCtlBlock)
 | 
						|
      : mCtlBlock(aCtlBlock) {}
 | 
						|
 | 
						|
  friend class NativeWeakPtrHolder<NativeImpl>;
 | 
						|
 | 
						|
 protected:
 | 
						|
  RefPtr<detail::NativeWeakPtrControlBlock<NativeImpl>> mCtlBlock;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * A pointer to an instance of this class should be stored in a Java object's
 | 
						|
 * JNIObject handle. New instances of native objects wrapped by NativeWeakPtr
 | 
						|
 * are created using the static methods of this class.
 | 
						|
 *
 | 
						|
 * Why do we have distinct methods here instead of using AttachNative like other
 | 
						|
 * pointer types that may be stored in JNIObject?
 | 
						|
 *
 | 
						|
 * Essentially, we want the creation and use of NativeWeakPtr to be as
 | 
						|
 * deliberate as possible. Forcing a different creation mechanism is part of
 | 
						|
 * that emphasis.
 | 
						|
 *
 | 
						|
 * Example:
 | 
						|
 *
 | 
						|
 * class NativeFoo {
 | 
						|
 *  public:
 | 
						|
 *   NativeFoo();
 | 
						|
 *   void Bar();
 | 
						|
 *   // The following method is required to be used with NativeWeakPtr
 | 
						|
 *   void OnWeakNonIntrusiveDetach(already_AddRefed<Runnable> aDisposer);
 | 
						|
 * };
 | 
						|
 *
 | 
						|
 * java::Object::LocalRef javaObj(...);
 | 
						|
 *
 | 
						|
 * // Create a new Foo that is attached to javaObj
 | 
						|
 * auto weakFoo = NativeWeakPtrHolder<NativeFoo>::Attach(javaObj);
 | 
						|
 *
 | 
						|
 * // Now I can save weakFoo, access it, do whatever I want
 | 
						|
 * if (auto accWeakFoo = weakFoo.Access()) {
 | 
						|
 *   accWeakFoo->Bar();
 | 
						|
 * }
 | 
						|
 *
 | 
						|
 * // Detach from javaObj and clean up
 | 
						|
 * weakFoo.Detach();
 | 
						|
 */
 | 
						|
template <typename NativeImpl>
 | 
						|
class MOZ_HEAP_CLASS NativeWeakPtrHolder final
 | 
						|
    : public NativeWeakPtr<NativeImpl> {
 | 
						|
  using Base = NativeWeakPtr<NativeImpl>;
 | 
						|
 | 
						|
 public:
 | 
						|
  using Accessor = typename Base::Accessor;
 | 
						|
  using StorageTraits =
 | 
						|
      typename detail::NativeWeakPtrControlBlock<NativeImpl>::StorageTraits;
 | 
						|
  using StorageType = typename StorageTraits::Type;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create a new NativeImpl object, wrap it in a NativeWeakPtr, and store it
 | 
						|
   * in the Java object's JNIObject handle.
 | 
						|
   *
 | 
						|
   * @return A NativeWeakPtr object that references the newly-attached object.
 | 
						|
   */
 | 
						|
  template <typename Cls, typename JNIType, typename... Args>
 | 
						|
  static NativeWeakPtr<NativeImpl> Attach(const Ref<Cls, JNIType>& aJavaObject,
 | 
						|
                                          Args&&... aArgs) {
 | 
						|
    MOZ_RELEASE_ASSERT(NS_IsMainThread());
 | 
						|
 | 
						|
    StorageType nativeImpl(new NativeImpl(std::forward<Args>(aArgs)...));
 | 
						|
    return AttachInternal(aJavaObject, std::move(nativeImpl));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Given a new NativeImpl object, wrap it in a NativeWeakPtr, and store it
 | 
						|
   * in the Java object's JNIObject handle.
 | 
						|
   *
 | 
						|
   * @return A NativeWeakPtr object that references the newly-attached object.
 | 
						|
   */
 | 
						|
  template <typename Cls, typename JNIType>
 | 
						|
  static NativeWeakPtr<NativeImpl> AttachExisting(
 | 
						|
      const Ref<Cls, JNIType>& aJavaObject,
 | 
						|
      already_AddRefed<NativeImpl> aNativeImpl) {
 | 
						|
    MOZ_RELEASE_ASSERT(NS_IsMainThread());
 | 
						|
 | 
						|
    StorageType nativeImpl(aNativeImpl);
 | 
						|
    return AttachInternal(aJavaObject, std::move(nativeImpl));
 | 
						|
  }
 | 
						|
 | 
						|
  ~NativeWeakPtrHolder() = default;
 | 
						|
 | 
						|
  MOZ_IMPLICIT NativeWeakPtrHolder(decltype(nullptr)) = delete;
 | 
						|
  NativeWeakPtrHolder(const NativeWeakPtrHolder&) = delete;
 | 
						|
  NativeWeakPtrHolder(NativeWeakPtrHolder&&) = delete;
 | 
						|
  NativeWeakPtrHolder& operator=(const NativeWeakPtrHolder&) = delete;
 | 
						|
  NativeWeakPtrHolder& operator=(NativeWeakPtrHolder&&) = delete;
 | 
						|
  NativeWeakPtrHolder& operator=(decltype(nullptr)) = delete;
 | 
						|
 | 
						|
 private:
 | 
						|
  template <typename Cls>
 | 
						|
  NativeWeakPtrHolder(const LocalRef<Cls>& aJavaObject,
 | 
						|
                      StorageType&& aNativeImpl)
 | 
						|
      : NativeWeakPtr<NativeImpl>(
 | 
						|
            do_AddRef(new NativeWeakPtrControlBlock<NativeImpl>(
 | 
						|
                aJavaObject, std::move(aNativeImpl)))) {}
 | 
						|
 | 
						|
  /**
 | 
						|
   * Internal function that actually wraps the native pointer, binds it to the
 | 
						|
   * JNIObject, and then returns the NativeWeakPtr result.
 | 
						|
   */
 | 
						|
  template <typename Cls, typename JNIType>
 | 
						|
  static NativeWeakPtr<NativeImpl> AttachInternal(
 | 
						|
      const Ref<Cls, JNIType>& aJavaObject, StorageType&& aPtr) {
 | 
						|
    auto localJavaObject = ToLocalRef(aJavaObject);
 | 
						|
    NativeWeakPtrHolder<NativeImpl>* holder =
 | 
						|
        new NativeWeakPtrHolder<NativeImpl>(localJavaObject, std::move(aPtr));
 | 
						|
    static_assert(
 | 
						|
        NativePtrPicker<NativeImpl>::value == NativePtrType::WEAK_NON_INTRUSIVE,
 | 
						|
        "This type is not compatible with mozilla::jni::NativeWeakPtr");
 | 
						|
    NativePtrTraits<NativeImpl>::Set(localJavaObject, holder);
 | 
						|
    return NativeWeakPtr<NativeImpl>(holder->mCtlBlock);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
namespace detail {
 | 
						|
 | 
						|
/**
 | 
						|
 * NativePtrTraits for the WEAK_NON_INTRUSIVE pointer type.
 | 
						|
 */
 | 
						|
template <class Impl>
 | 
						|
struct NativePtrTraits<Impl, /* Type = */ NativePtrType::WEAK_NON_INTRUSIVE> {
 | 
						|
  using AccessorType = typename NativeWeakPtrHolder<Impl>::Accessor;
 | 
						|
  using HandleType = NativeWeakPtrHolder<Impl>*;
 | 
						|
  using RefType = NativeWeakPtrHolder<Impl>* const;
 | 
						|
 | 
						|
  static RefType Get(JNIEnv* env, jobject instance) {
 | 
						|
    return GetHandle(env, instance);
 | 
						|
  }
 | 
						|
 | 
						|
  template <typename Cls>
 | 
						|
  static RefType Get(const LocalRef<Cls>& instance) {
 | 
						|
    return GetHandle(instance.Env(), instance.Get());
 | 
						|
  }
 | 
						|
 | 
						|
  static AccessorType Access(RefType aPtr) { return aPtr->Access(); }
 | 
						|
 | 
						|
  template <typename Cls>
 | 
						|
  static void Set(const LocalRef<Cls>& instance, HandleType ptr) {
 | 
						|
    MOZ_RELEASE_ASSERT(NS_IsMainThread());
 | 
						|
    const uintptr_t handle = reinterpret_cast<uintptr_t>(ptr);
 | 
						|
    Clear(instance);
 | 
						|
    SetNativeHandle(instance.Env(), instance.Get(), handle);
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
  }
 | 
						|
 | 
						|
  template <typename Cls>
 | 
						|
  static void Clear(const LocalRef<Cls>& instance) {
 | 
						|
    auto ptr = reinterpret_cast<HandleType>(
 | 
						|
        GetNativeHandle(instance.Env(), instance.Get()));
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(instance.Env());
 | 
						|
 | 
						|
    if (!ptr) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    ptr->Detach();
 | 
						|
  }
 | 
						|
 | 
						|
  // This call is not safe to do unless we know for sure that instance's
 | 
						|
  // native handle has not changed. It is up to NativeWeakPtrDetachRunnable
 | 
						|
  // to perform this check.
 | 
						|
  template <typename Cls>
 | 
						|
  static void ClearFinish(const LocalRef<Cls>& instance) {
 | 
						|
    MOZ_RELEASE_ASSERT(NS_IsMainThread());
 | 
						|
    JNIEnv* const env = instance.Env();
 | 
						|
    auto ptr =
 | 
						|
        reinterpret_cast<HandleType>(GetNativeHandle(env, instance.Get()));
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(env);
 | 
						|
    MOZ_RELEASE_ASSERT(!!ptr);
 | 
						|
 | 
						|
    SetNativeHandle(env, instance.Get(), 0);
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(env);
 | 
						|
    // Deletion of ptr is done by the caller
 | 
						|
  }
 | 
						|
 | 
						|
  // The call is stale if the native object has been destroyed on the
 | 
						|
  // Gecko side, but the Java object is still attached to it through
 | 
						|
  // a weak pointer. Stale calls should be discarded. Note that it's
 | 
						|
  // an error if holder is nullptr here; we return false but the
 | 
						|
  // native call will throw an error.
 | 
						|
  template <class LocalRef>
 | 
						|
  static bool IsStale(const LocalRef& instance) {
 | 
						|
    JNIEnv* const env = mozilla::jni::GetEnvForThread();
 | 
						|
 | 
						|
    // We cannot use Get here because that method throws an exception when the
 | 
						|
    // object is null, which is a valid state for a stale call.
 | 
						|
    const auto holder =
 | 
						|
        reinterpret_cast<HandleType>(GetNativeHandle(env, instance.Get()));
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(env);
 | 
						|
 | 
						|
    if (!holder || !holder->IsAttached()) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    auto acc(holder->Access());
 | 
						|
    return !acc;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  static HandleType GetHandle(JNIEnv* env, jobject instance) {
 | 
						|
    return reinterpret_cast<HandleType>(
 | 
						|
        CheckNativeHandle<Impl>(env, GetNativeHandle(env, instance)));
 | 
						|
  }
 | 
						|
 | 
						|
  template <typename Cls>
 | 
						|
  static HandleType GetHandle(const LocalRef<Cls>& instance) {
 | 
						|
    return GetHandle(instance.Env(), instance.Get());
 | 
						|
  }
 | 
						|
 | 
						|
  friend class NativeWeakPtrHolder<Impl>;
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace detail
 | 
						|
 | 
						|
using namespace detail;
 | 
						|
 | 
						|
/**
 | 
						|
 * For JNI native methods that are dispatched to a proxy, i.e. using
 | 
						|
 * @WrapForJNI(dispatchTo = "proxy"), the implementing C++ class must provide a
 | 
						|
 * OnNativeCall member. Subsequently, every native call is automatically
 | 
						|
 * wrapped in a functor object, and the object is passed to OnNativeCall. The
 | 
						|
 * OnNativeCall implementation can choose to invoke the call, save it, dispatch
 | 
						|
 * it to a different thread, etc. Each copy of functor may only be invoked
 | 
						|
 * once.
 | 
						|
 *
 | 
						|
 * class MyClass : public MyJavaClass::Natives<MyClass>
 | 
						|
 * {
 | 
						|
 *     // ...
 | 
						|
 *
 | 
						|
 *     template<class Functor>
 | 
						|
 *     class ProxyRunnable final : public Runnable
 | 
						|
 *     {
 | 
						|
 *         Functor mCall;
 | 
						|
 *     public:
 | 
						|
 *         ProxyRunnable(Functor&& call) : mCall(std::move(call)) {}
 | 
						|
 *         virtual void run() override { mCall(); }
 | 
						|
 *     };
 | 
						|
 *
 | 
						|
 * public:
 | 
						|
 *     template<class Functor>
 | 
						|
 *     static void OnNativeCall(Functor&& call)
 | 
						|
 *     {
 | 
						|
 *         RunOnAnotherThread(new ProxyRunnable(std::move(call)));
 | 
						|
 *     }
 | 
						|
 * };
 | 
						|
 */
 | 
						|
 | 
						|
namespace detail {
 | 
						|
 | 
						|
// ProxyArg is used to handle JNI ref arguments for proxies. Because a proxied
 | 
						|
// call may happen outside of the original JNI native call, we must save all
 | 
						|
// JNI ref arguments as global refs to avoid the arguments going out of scope.
 | 
						|
template <typename T>
 | 
						|
struct ProxyArg {
 | 
						|
  static_assert(std::is_trivial_v<T> && std::is_standard_layout_v<T>,
 | 
						|
                "T must be primitive type");
 | 
						|
 | 
						|
  // Primitive types can be saved by value.
 | 
						|
  typedef T Type;
 | 
						|
  typedef typename TypeAdapter<T>::JNIType JNIType;
 | 
						|
 | 
						|
  static void Clear(JNIEnv* env, Type&) {}
 | 
						|
 | 
						|
  static Type From(JNIEnv* env, JNIType val) {
 | 
						|
    return TypeAdapter<T>::ToNative(env, val);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
template <class C, typename T>
 | 
						|
struct ProxyArg<Ref<C, T>> {
 | 
						|
  // Ref types need to be saved by global ref.
 | 
						|
  typedef typename C::GlobalRef Type;
 | 
						|
  typedef typename TypeAdapter<Ref<C, T>>::JNIType JNIType;
 | 
						|
 | 
						|
  static void Clear(JNIEnv* env, Type& ref) { ref.Clear(env); }
 | 
						|
 | 
						|
  static Type From(JNIEnv* env, JNIType val) {
 | 
						|
    return Type(env, C::Ref::From(val));
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
template <typename C>
 | 
						|
struct ProxyArg<const C&> : ProxyArg<C> {};
 | 
						|
template <>
 | 
						|
struct ProxyArg<StringParam> : ProxyArg<String::Ref> {};
 | 
						|
template <class C>
 | 
						|
struct ProxyArg<LocalRef<C>> : ProxyArg<typename C::Ref> {};
 | 
						|
 | 
						|
// ProxyNativeCall implements the functor object that is passed to OnNativeCall
 | 
						|
template <class Impl, class Owner, bool IsStatic,
 | 
						|
          bool HasThisArg /* has instance/class local ref in the call */,
 | 
						|
          typename... Args>
 | 
						|
class ProxyNativeCall {
 | 
						|
  // "this arg" refers to the Class::LocalRef (for static methods) or
 | 
						|
  // Owner::LocalRef (for instance methods) that we optionally (as indicated
 | 
						|
  // by HasThisArg) pass into the destination C++ function.
 | 
						|
  using ThisArgClass = std::conditional_t<IsStatic, Class, Owner>;
 | 
						|
  using ThisArgJNIType = std::conditional_t<IsStatic, jclass, jobject>;
 | 
						|
 | 
						|
  // Type signature of the destination C++ function, which matches the
 | 
						|
  // Method template parameter in NativeStubImpl::Wrap.
 | 
						|
  using NativeCallType = std::conditional_t<
 | 
						|
      IsStatic,
 | 
						|
      std::conditional_t<HasThisArg, void (*)(const Class::LocalRef&, Args...),
 | 
						|
                         void (*)(Args...)>,
 | 
						|
      std::conditional_t<
 | 
						|
          HasThisArg, void (Impl::*)(const typename Owner::LocalRef&, Args...),
 | 
						|
          void (Impl::*)(Args...)>>;
 | 
						|
 | 
						|
  // Destination C++ function.
 | 
						|
  NativeCallType mNativeCall;
 | 
						|
  // Saved this arg.
 | 
						|
  typename ThisArgClass::GlobalRef mThisArg;
 | 
						|
  // Saved arguments.
 | 
						|
  std::tuple<typename ProxyArg<Args>::Type...> mArgs;
 | 
						|
 | 
						|
  // We cannot use IsStatic and HasThisArg directly (without going through
 | 
						|
  // extra hoops) because GCC complains about invalid overloads, so we use
 | 
						|
  // another pair of template parameters, Static and ThisArg.
 | 
						|
 | 
						|
  template <bool Static, bool ThisArg, size_t... Indices>
 | 
						|
  std::enable_if_t<Static && ThisArg, void> Call(
 | 
						|
      const Class::LocalRef& cls, std::index_sequence<Indices...>) const {
 | 
						|
    (*mNativeCall)(cls, std::get<Indices>(mArgs)...);
 | 
						|
  }
 | 
						|
 | 
						|
  template <bool Static, bool ThisArg, size_t... Indices>
 | 
						|
  std::enable_if_t<Static && !ThisArg, void> Call(
 | 
						|
      const Class::LocalRef& cls, std::index_sequence<Indices...>) const {
 | 
						|
    (*mNativeCall)(std::get<Indices>(mArgs)...);
 | 
						|
  }
 | 
						|
 | 
						|
  template <bool Static, bool ThisArg, size_t... Indices>
 | 
						|
  std::enable_if_t<!Static && ThisArg, void> Call(
 | 
						|
      const typename Owner::LocalRef& inst,
 | 
						|
      std::index_sequence<Indices...>) const {
 | 
						|
    auto impl = NativePtrTraits<Impl>::Access(NativePtrTraits<Impl>::Get(inst));
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(inst.Env());
 | 
						|
    (impl->*mNativeCall)(inst, std::get<Indices>(mArgs)...);
 | 
						|
  }
 | 
						|
 | 
						|
  template <bool Static, bool ThisArg, size_t... Indices>
 | 
						|
  std::enable_if_t<!Static && !ThisArg, void> Call(
 | 
						|
      const typename Owner::LocalRef& inst,
 | 
						|
      std::index_sequence<Indices...>) const {
 | 
						|
    auto impl = NativePtrTraits<Impl>::Access(NativePtrTraits<Impl>::Get(inst));
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(inst.Env());
 | 
						|
    (impl->*mNativeCall)(std::get<Indices>(mArgs)...);
 | 
						|
  }
 | 
						|
 | 
						|
  template <size_t... Indices>
 | 
						|
  void Clear(JNIEnv* env, std::index_sequence<Indices...>) {
 | 
						|
    int dummy[] = {
 | 
						|
        (ProxyArg<Args>::Clear(env, std::get<Indices>(mArgs)), 0)...};
 | 
						|
    mozilla::Unused << dummy;
 | 
						|
  }
 | 
						|
 | 
						|
  static decltype(auto) GetNativeObject(Class::Param thisArg) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  static decltype(auto) GetNativeObject(typename Owner::Param thisArg) {
 | 
						|
    return NativePtrTraits<Impl>::Access(
 | 
						|
        NativePtrTraits<Impl>::Get(GetEnvForThread(), thisArg.Get()));
 | 
						|
  }
 | 
						|
 | 
						|
 public:
 | 
						|
  // The class that implements the call target.
 | 
						|
  typedef Impl TargetClass;
 | 
						|
  typedef typename ThisArgClass::Param ThisArgType;
 | 
						|
 | 
						|
  static const bool isStatic = IsStatic;
 | 
						|
 | 
						|
  ProxyNativeCall(ThisArgJNIType thisArg, NativeCallType nativeCall,
 | 
						|
                  JNIEnv* env, typename ProxyArg<Args>::JNIType... args)
 | 
						|
      : mNativeCall(nativeCall),
 | 
						|
        mThisArg(env, ThisArgClass::Ref::From(thisArg)),
 | 
						|
        mArgs(ProxyArg<Args>::From(env, args)...) {}
 | 
						|
 | 
						|
  ProxyNativeCall(ProxyNativeCall&&) = default;
 | 
						|
  ProxyNativeCall(const ProxyNativeCall&) = default;
 | 
						|
 | 
						|
  // Get class ref for static calls or object ref for instance calls.
 | 
						|
  typename ThisArgClass::Param GetThisArg() const { return mThisArg; }
 | 
						|
 | 
						|
  // Get the native object targeted by this call.
 | 
						|
  // Returns nullptr for static calls.
 | 
						|
  decltype(auto) GetNativeObject() const { return GetNativeObject(mThisArg); }
 | 
						|
 | 
						|
  // Return if target is the given function pointer / pointer-to-member.
 | 
						|
  // Because we can only compare pointers of the same type, we use a
 | 
						|
  // templated overload that is chosen only if given a different type of
 | 
						|
  // pointer than our target pointer type.
 | 
						|
  bool IsTarget(NativeCallType call) const { return call == mNativeCall; }
 | 
						|
  template <typename T>
 | 
						|
  bool IsTarget(T&&) const {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Redirect the call to another function / class member with the same
 | 
						|
  // signature as the original target. Crash if given a wrong signature.
 | 
						|
  void SetTarget(NativeCallType call) { mNativeCall = call; }
 | 
						|
  template <typename T>
 | 
						|
  void SetTarget(T&&) const {
 | 
						|
    MOZ_CRASH();
 | 
						|
  }
 | 
						|
 | 
						|
  void operator()() {
 | 
						|
    JNIEnv* const env = GetEnvForThread();
 | 
						|
    typename ThisArgClass::LocalRef thisArg(env, mThisArg);
 | 
						|
    Call<IsStatic, HasThisArg>(thisArg, std::index_sequence_for<Args...>{});
 | 
						|
 | 
						|
    // Clear all saved global refs. We do this after the call is invoked,
 | 
						|
    // and not inside the destructor because we already have a JNIEnv here,
 | 
						|
    // so it's more efficient to clear out the saved args here. The
 | 
						|
    // downside is that the call can only be invoked once.
 | 
						|
    Clear(env, std::index_sequence_for<Args...>{});
 | 
						|
    mThisArg.Clear(env);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
template <class Impl, bool HasThisArg, typename... Args>
 | 
						|
struct Dispatcher {
 | 
						|
  template <class Traits, bool IsStatic = Traits::isStatic,
 | 
						|
            typename... ProxyArgs>
 | 
						|
  static std::enable_if_t<Traits::dispatchTarget == DispatchTarget::PROXY, void>
 | 
						|
  Run(ProxyArgs&&... args) {
 | 
						|
    Impl::OnNativeCall(
 | 
						|
        ProxyNativeCall<Impl, typename Traits::Owner, IsStatic, HasThisArg,
 | 
						|
                        Args...>(std::forward<ProxyArgs>(args)...));
 | 
						|
  }
 | 
						|
 | 
						|
  template <class Traits, bool IsStatic = Traits::isStatic, typename ThisArg,
 | 
						|
            typename... ProxyArgs>
 | 
						|
  static std::enable_if_t<
 | 
						|
      Traits::dispatchTarget == DispatchTarget::GECKO_PRIORITY, void>
 | 
						|
  Run(ThisArg thisArg, ProxyArgs&&... args) {
 | 
						|
    // For a static method, do not forward the "this arg" (i.e. the class
 | 
						|
    // local ref) if the implementation does not request it. This saves us
 | 
						|
    // a pair of calls to add/delete global ref.
 | 
						|
    auto proxy =
 | 
						|
        ProxyNativeCall<Impl, typename Traits::Owner, IsStatic, HasThisArg,
 | 
						|
                        Args...>((HasThisArg || !IsStatic) ? thisArg : nullptr,
 | 
						|
                                 std::forward<ProxyArgs>(args)...);
 | 
						|
    DispatchToGeckoPriorityQueue(
 | 
						|
        NS_NewRunnableFunction("PriorityNativeCall", std::move(proxy)));
 | 
						|
  }
 | 
						|
 | 
						|
  template <class Traits, bool IsStatic = Traits::isStatic, typename ThisArg,
 | 
						|
            typename... ProxyArgs>
 | 
						|
  static std::enable_if_t<Traits::dispatchTarget == DispatchTarget::GECKO, void>
 | 
						|
  Run(ThisArg thisArg, ProxyArgs&&... args) {
 | 
						|
    // For a static method, do not forward the "this arg" (i.e. the class
 | 
						|
    // local ref) if the implementation does not request it. This saves us
 | 
						|
    // a pair of calls to add/delete global ref.
 | 
						|
    auto proxy =
 | 
						|
        ProxyNativeCall<Impl, typename Traits::Owner, IsStatic, HasThisArg,
 | 
						|
                        Args...>((HasThisArg || !IsStatic) ? thisArg : nullptr,
 | 
						|
                                 std::forward<ProxyArgs>(args)...);
 | 
						|
    NS_DispatchToMainThread(
 | 
						|
        NS_NewRunnableFunction("GeckoNativeCall", std::move(proxy)));
 | 
						|
  }
 | 
						|
 | 
						|
  template <class Traits, bool IsStatic = false, typename... ProxyArgs>
 | 
						|
  static std::enable_if_t<Traits::dispatchTarget == DispatchTarget::CURRENT,
 | 
						|
                          void>
 | 
						|
  Run(ProxyArgs&&... args) {
 | 
						|
    MOZ_CRASH("Unreachable code");
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace detail
 | 
						|
 | 
						|
// Wrapper methods that convert arguments from the JNI types to the native
 | 
						|
// types, e.g. from jobject to jni::Object::Ref. For instance methods, the
 | 
						|
// wrapper methods also convert calls to calls on objects.
 | 
						|
//
 | 
						|
// We need specialization for static/non-static because the two have different
 | 
						|
// signatures (jobject vs jclass and Impl::*Method vs *Method).
 | 
						|
// We need specialization for return type, because void return type requires
 | 
						|
// us to not deal with the return value.
 | 
						|
 | 
						|
// Bug 1207642 - Work around Dalvik bug by realigning stack on JNI entry
 | 
						|
#ifdef __i386__
 | 
						|
#  define MOZ_JNICALL JNICALL __attribute__((force_align_arg_pointer))
 | 
						|
#else
 | 
						|
#  define MOZ_JNICALL JNICALL
 | 
						|
#endif
 | 
						|
 | 
						|
template <class Traits, class Impl, class Args = typename Traits::Args>
 | 
						|
class NativeStub;
 | 
						|
 | 
						|
template <class Traits, class Impl, typename... Args>
 | 
						|
class NativeStub<Traits, Impl, jni::Args<Args...>> {
 | 
						|
  using Owner = typename Traits::Owner;
 | 
						|
  using ReturnType = typename Traits::ReturnType;
 | 
						|
 | 
						|
  static constexpr bool isStatic = Traits::isStatic;
 | 
						|
  static constexpr bool isVoid = std::is_void_v<ReturnType>;
 | 
						|
 | 
						|
  struct VoidType {
 | 
						|
    using JNIType = void;
 | 
						|
  };
 | 
						|
  using ReturnJNIType =
 | 
						|
      typename std::conditional_t<isVoid, VoidType,
 | 
						|
                                  TypeAdapter<ReturnType>>::JNIType;
 | 
						|
 | 
						|
  using ReturnTypeForNonVoidInstance =
 | 
						|
      std::conditional_t<!isStatic && !isVoid, ReturnType, VoidType>;
 | 
						|
  using ReturnTypeForVoidInstance =
 | 
						|
      std::conditional_t<!isStatic && isVoid, ReturnType, VoidType&>;
 | 
						|
  using ReturnTypeForNonVoidStatic =
 | 
						|
      std::conditional_t<isStatic && !isVoid, ReturnType, VoidType>;
 | 
						|
  using ReturnTypeForVoidStatic =
 | 
						|
      std::conditional_t<isStatic && isVoid, ReturnType, VoidType&>;
 | 
						|
 | 
						|
  static_assert(Traits::dispatchTarget == DispatchTarget::CURRENT || isVoid,
 | 
						|
                "Dispatched calls must have void return type");
 | 
						|
 | 
						|
 public:
 | 
						|
  // Non-void instance method
 | 
						|
  template <ReturnTypeForNonVoidInstance (Impl::*Method)(Args...)>
 | 
						|
  static MOZ_JNICALL ReturnJNIType
 | 
						|
  Wrap(JNIEnv* env, jobject instance,
 | 
						|
       typename TypeAdapter<Args>::JNIType... args) {
 | 
						|
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
 | 
						|
 | 
						|
    auto impl = NativePtrTraits<Impl>::Access(
 | 
						|
        NativePtrTraits<Impl>::Get(env, instance));
 | 
						|
    if (!impl) {
 | 
						|
      // There is a pending JNI exception at this point.
 | 
						|
      return ReturnJNIType();
 | 
						|
    }
 | 
						|
    return TypeAdapter<ReturnType>::FromNative(
 | 
						|
        env, (impl->*Method)(TypeAdapter<Args>::ToNative(env, args)...));
 | 
						|
  }
 | 
						|
 | 
						|
  // Non-void instance method with instance reference
 | 
						|
  template <ReturnTypeForNonVoidInstance (Impl::*Method)(
 | 
						|
      const typename Owner::LocalRef&, Args...)>
 | 
						|
  static MOZ_JNICALL ReturnJNIType
 | 
						|
  Wrap(JNIEnv* env, jobject instance,
 | 
						|
       typename TypeAdapter<Args>::JNIType... args) {
 | 
						|
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
 | 
						|
 | 
						|
    auto impl = NativePtrTraits<Impl>::Access(
 | 
						|
        NativePtrTraits<Impl>::Get(env, instance));
 | 
						|
    if (!impl) {
 | 
						|
      // There is a pending JNI exception at this point.
 | 
						|
      return ReturnJNIType();
 | 
						|
    }
 | 
						|
    auto self = Owner::LocalRef::Adopt(env, instance);
 | 
						|
    const auto res = TypeAdapter<ReturnType>::FromNative(
 | 
						|
        env, (impl->*Method)(self, TypeAdapter<Args>::ToNative(env, args)...));
 | 
						|
    self.Forget();
 | 
						|
    return res;
 | 
						|
  }
 | 
						|
 | 
						|
  // Void instance method
 | 
						|
  template <ReturnTypeForVoidInstance (Impl::*Method)(Args...)>
 | 
						|
  static MOZ_JNICALL void Wrap(JNIEnv* env, jobject instance,
 | 
						|
                               typename TypeAdapter<Args>::JNIType... args) {
 | 
						|
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
 | 
						|
 | 
						|
    if (Traits::dispatchTarget != DispatchTarget::CURRENT) {
 | 
						|
      Dispatcher<Impl, /* HasThisArg */ false, Args...>::template Run<Traits>(
 | 
						|
          instance, Method, env, args...);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    auto impl = NativePtrTraits<Impl>::Access(
 | 
						|
        NativePtrTraits<Impl>::Get(env, instance));
 | 
						|
    if (!impl) {
 | 
						|
      // There is a pending JNI exception at this point.
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    (impl->*Method)(TypeAdapter<Args>::ToNative(env, args)...);
 | 
						|
  }
 | 
						|
 | 
						|
  // Void instance method with instance reference
 | 
						|
  template <ReturnTypeForVoidInstance (Impl::*Method)(
 | 
						|
      const typename Owner::LocalRef&, Args...)>
 | 
						|
  static MOZ_JNICALL void Wrap(JNIEnv* env, jobject instance,
 | 
						|
                               typename TypeAdapter<Args>::JNIType... args) {
 | 
						|
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
 | 
						|
 | 
						|
    if (Traits::dispatchTarget != DispatchTarget::CURRENT) {
 | 
						|
      Dispatcher<Impl, /* HasThisArg */ true, Args...>::template Run<Traits>(
 | 
						|
          instance, Method, env, args...);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    auto impl = NativePtrTraits<Impl>::Access(
 | 
						|
        NativePtrTraits<Impl>::Get(env, instance));
 | 
						|
    if (!impl) {
 | 
						|
      // There is a pending JNI exception at this point.
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    auto self = Owner::LocalRef::Adopt(env, instance);
 | 
						|
    (impl->*Method)(self, TypeAdapter<Args>::ToNative(env, args)...);
 | 
						|
    self.Forget();
 | 
						|
  }
 | 
						|
 | 
						|
  // Overload for DisposeNative
 | 
						|
  template <ReturnTypeForVoidInstance (*DisposeNative)(
 | 
						|
      const typename Owner::LocalRef&)>
 | 
						|
  static MOZ_JNICALL void Wrap(JNIEnv* env, jobject instance) {
 | 
						|
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
 | 
						|
 | 
						|
    if (Traits::dispatchTarget != DispatchTarget::CURRENT) {
 | 
						|
      using LocalRef = typename Owner::LocalRef;
 | 
						|
      Dispatcher<Impl, /* HasThisArg */ false, const LocalRef&>::template Run<
 | 
						|
          Traits, /* IsStatic */ true>(
 | 
						|
          /* ThisArg */ nullptr, DisposeNative, env, instance);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    auto self = Owner::LocalRef::Adopt(env, instance);
 | 
						|
    DisposeNative(self);
 | 
						|
    self.Forget();
 | 
						|
  }
 | 
						|
 | 
						|
  // Non-void static method
 | 
						|
  template <ReturnTypeForNonVoidStatic (*Method)(Args...)>
 | 
						|
  static MOZ_JNICALL ReturnJNIType
 | 
						|
  Wrap(JNIEnv* env, jclass, typename TypeAdapter<Args>::JNIType... args) {
 | 
						|
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
 | 
						|
 | 
						|
    return TypeAdapter<ReturnType>::FromNative(
 | 
						|
        env, (*Method)(TypeAdapter<Args>::ToNative(env, args)...));
 | 
						|
  }
 | 
						|
 | 
						|
  // Non-void static method with class reference
 | 
						|
  template <ReturnTypeForNonVoidStatic (*Method)(const Class::LocalRef&,
 | 
						|
                                                 Args...)>
 | 
						|
  static MOZ_JNICALL ReturnJNIType
 | 
						|
  Wrap(JNIEnv* env, jclass cls, typename TypeAdapter<Args>::JNIType... args) {
 | 
						|
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
 | 
						|
 | 
						|
    auto clazz = Class::LocalRef::Adopt(env, cls);
 | 
						|
    const auto res = TypeAdapter<ReturnType>::FromNative(
 | 
						|
        env, (*Method)(clazz, TypeAdapter<Args>::ToNative(env, args)...));
 | 
						|
    clazz.Forget();
 | 
						|
    return res;
 | 
						|
  }
 | 
						|
 | 
						|
  // Void static method
 | 
						|
  template <ReturnTypeForVoidStatic (*Method)(Args...)>
 | 
						|
  static MOZ_JNICALL void Wrap(JNIEnv* env, jclass cls,
 | 
						|
                               typename TypeAdapter<Args>::JNIType... args) {
 | 
						|
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
 | 
						|
 | 
						|
    if (Traits::dispatchTarget != DispatchTarget::CURRENT) {
 | 
						|
      Dispatcher<Impl, /* HasThisArg */ false, Args...>::template Run<Traits>(
 | 
						|
          cls, Method, env, args...);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    (*Method)(TypeAdapter<Args>::ToNative(env, args)...);
 | 
						|
  }
 | 
						|
 | 
						|
  // Void static method with class reference
 | 
						|
  template <ReturnTypeForVoidStatic (*Method)(const Class::LocalRef&, Args...)>
 | 
						|
  static MOZ_JNICALL void Wrap(JNIEnv* env, jclass cls,
 | 
						|
                               typename TypeAdapter<Args>::JNIType... args) {
 | 
						|
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
 | 
						|
 | 
						|
    if (Traits::dispatchTarget != DispatchTarget::CURRENT) {
 | 
						|
      Dispatcher<Impl, /* HasThisArg */ true, Args...>::template Run<Traits>(
 | 
						|
          cls, Method, env, args...);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    auto clazz = Class::LocalRef::Adopt(env, cls);
 | 
						|
    (*Method)(clazz, TypeAdapter<Args>::ToNative(env, args)...);
 | 
						|
    clazz.Forget();
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
// Generate a JNINativeMethod from a native
 | 
						|
// method's traits class and a wrapped stub.
 | 
						|
template <class Traits, typename Ret, typename... Args>
 | 
						|
constexpr JNINativeMethod MakeNativeMethod(MOZ_JNICALL Ret (*stub)(JNIEnv*,
 | 
						|
                                                                   Args...)) {
 | 
						|
  return {Traits::name, Traits::signature, reinterpret_cast<void*>(stub)};
 | 
						|
}
 | 
						|
 | 
						|
// Class inherited by implementing class.
 | 
						|
template <class Cls, class Impl>
 | 
						|
class NativeImpl {
 | 
						|
  typedef typename Cls::template Natives<Impl> Natives;
 | 
						|
 | 
						|
  static bool sInited;
 | 
						|
 | 
						|
 public:
 | 
						|
  static void Init() {
 | 
						|
    if (sInited) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    const auto& ctx = typename Cls::Context();
 | 
						|
    ctx.Env()->RegisterNatives(
 | 
						|
        ctx.ClassRef(), Natives::methods,
 | 
						|
        sizeof(Natives::methods) / sizeof(Natives::methods[0]));
 | 
						|
    MOZ_CATCH_JNI_EXCEPTION(ctx.Env());
 | 
						|
    sInited = true;
 | 
						|
  }
 | 
						|
 | 
						|
 protected:
 | 
						|
  // Associate a C++ instance with a Java instance.
 | 
						|
  static void AttachNative(const typename Cls::LocalRef& instance,
 | 
						|
                           SupportsWeakPtr* ptr) {
 | 
						|
    static_assert(NativePtrPicker<Impl>::value == NativePtrType::WEAK_INTRUSIVE,
 | 
						|
                  "Use another AttachNative for non-WeakPtr usage");
 | 
						|
    return NativePtrTraits<Impl>::Set(instance, static_cast<Impl*>(ptr));
 | 
						|
  }
 | 
						|
 | 
						|
  static void AttachNative(const typename Cls::LocalRef& instance,
 | 
						|
                           UniquePtr<Impl>&& ptr) {
 | 
						|
    static_assert(NativePtrPicker<Impl>::value == NativePtrType::OWNING,
 | 
						|
                  "Use another AttachNative for WeakPtr or RefPtr usage");
 | 
						|
    return NativePtrTraits<Impl>::Set(instance, std::move(ptr));
 | 
						|
  }
 | 
						|
 | 
						|
  static void AttachNative(const typename Cls::LocalRef& instance, Impl* ptr) {
 | 
						|
    static_assert(NativePtrPicker<Impl>::value == NativePtrType::REFPTR,
 | 
						|
                  "Use another AttachNative for non-RefPtr usage");
 | 
						|
    return NativePtrTraits<Impl>::Set(instance, ptr);
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the C++ instance associated with a Java instance.
 | 
						|
  // There is always a pending exception if the return value is nullptr.
 | 
						|
  static decltype(auto) GetNative(const typename Cls::LocalRef& instance) {
 | 
						|
    return NativePtrTraits<Impl>::Get(instance);
 | 
						|
  }
 | 
						|
 | 
						|
  static void DisposeNative(const typename Cls::LocalRef& instance) {
 | 
						|
    NativePtrTraits<Impl>::Clear(instance);
 | 
						|
  }
 | 
						|
 | 
						|
  NativeImpl() {
 | 
						|
    // Initialize on creation if not already initialized.
 | 
						|
    Init();
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
// Define static member.
 | 
						|
template <class C, class I>
 | 
						|
bool NativeImpl<C, I>::sInited;
 | 
						|
 | 
						|
}  // namespace jni
 | 
						|
}  // namespace mozilla
 | 
						|
 | 
						|
#endif  // mozilla_jni_Natives_h__
 |