Update fbjni from upstream

Reviewed By: @mkonicek

Differential Revision: D2517281

fb-gh-sync-id: 9deeae6821f13394a2886d6d86781b4f563aadf6
This commit is contained in:
Marc Horowitz 2015-10-08 08:42:28 -07:00 committed by facebook-github-bot-3
parent e3e9be9efb
commit 23a16f60f8
10 changed files with 140 additions and 74 deletions

View File

@ -149,33 +149,36 @@ DEFINE_PRIMITIVE_METHODS(jdouble, Double)
#define DEFINE_PRIMITIVE_ARRAY_UTILS(TYPE, NAME) \
\
local_ref<j ## TYPE ## Array> make_ ## TYPE ## _array(jsize size) { \
auto array = internal::getEnv()->New ## NAME ## Array(size); \
FACEBOOK_JNI_THROW_EXCEPTION_IF(!array); \
return adopt_local(array); \
} \
\
j ## TYPE* \
JObjectWrapper<j ## TYPE ## Array>::getRegion(jsize start, jsize length, j ## TYPE* buf) { \
local_ref<j ## TYPE ## Array> JArray ## NAME::newArray(size_t count) { \
return make_ ## TYPE ## _array(count); \
} \
\
j ## TYPE* JArray ## NAME::getRegion(jsize start, jsize length, j ## TYPE* buf) { \
internal::getEnv()->Get ## NAME ## ArrayRegion(self(), start, length, buf); \
FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); \
return buf; \
} \
\
std::unique_ptr<j ## TYPE[]> \
JObjectWrapper<j ## TYPE ## Array>::getRegion(jsize start, jsize length) { \
std::unique_ptr<j ## TYPE[]> JArray ## NAME::getRegion(jsize start, jsize length) { \
auto buf = std::unique_ptr<j ## TYPE[]>{new j ## TYPE[length]}; \
internal::getEnv()->Get ## NAME ## ArrayRegion(self(), start, length, buf.get()); \
FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); \
return buf; \
} \
\
void JObjectWrapper<j ## TYPE ## Array>::setRegion(jsize start, jsize length, j ## TYPE* buf) { \
void JArray ## NAME::setRegion(jsize start, jsize length, const j ## TYPE* buf) { \
internal::getEnv()->Set ## NAME ## ArrayRegion(self(), start, length, buf); \
FACEBOOK_JNI_THROW_PENDING_EXCEPTION(); \
} \
\
PinnedPrimitiveArray<j ## TYPE> JObjectWrapper<j ## TYPE ## Array>::pin() { \
PinnedPrimitiveArray<j ## TYPE> JArray ## NAME::pin() { \
return PinnedPrimitiveArray<j ## TYPE>{self()}; \
} \

View File

@ -16,8 +16,8 @@
#include <jni.h>
#include "../Environment.h"
#include "../ALog.h"
#include <jni/Environment.h>
#include <jni/ALog.h>
/// @cond INTERNAL

View File

@ -304,17 +304,9 @@ inline ElementProxy<T>::ElementProxy::operator local_ref<T> () {
return target_->getElement(idx_);
}
template<typename T>
inline std::string JObjectWrapper<jtypeArray<T>>::bareClassName() {
// Use the initializer to strip off the leading and trailing character.
const char* className = JObjectWrapper<T>::kJavaDescriptor;
return std::string(className + 1, strlen(className) - 2);
}
template<typename T>
local_ref<jtypeArray<T>> JObjectWrapper<jtypeArray<T>>::newArray(size_t size) {
static auto elementClass = findClassStatic(
JObjectWrapper<jtypeArray<T>>::bareClassName().c_str());
static auto elementClass = findClassStatic(jtype_traits<T>::base_name().c_str());
const auto env = internal::getEnv();
auto rawArray = env->NewObjectArray(size, elementClass.get(), nullptr);
FACEBOOK_JNI_THROW_EXCEPTION_IF(!rawArray);
@ -435,15 +427,15 @@ DECLARE_PRIMITIVE_METHODS(jdouble, Double)
#pragma pop_macro("DECLARE_PRIMITIVE_METHODS")
template<typename T>
inline alias_ref<jclass> JavaClass<T>::javaClassStatic() {
template<typename T, typename Base>
inline alias_ref<jclass> JavaClass<T, Base>::javaClassStatic() {
static auto cls = findClassStatic(
std::string(T::kJavaDescriptor + 1, strlen(T::kJavaDescriptor) - 2).c_str());
return cls;
}
template<typename T>
inline local_ref<jclass> JavaClass<T>::javaClassLocal() {
template<typename T, typename Base>
inline local_ref<jclass> JavaClass<T, Base>::javaClassLocal() {
std::string className(T::kJavaDescriptor + 1, strlen(T::kJavaDescriptor) - 2);
return findClassLocal(className.c_str());
}

View File

@ -292,7 +292,7 @@ class JObjectWrapper<jtypeArray<T>> : public JObjectWrapper<jobject> {
public:
static constexpr const char* kJavaDescriptor = nullptr;
static std::string get_instantiated_java_descriptor() {
return jtype_traits<T>::array_descriptor();
return "[" + jtype_traits<T>::descriptor();
};
using JObjectWrapper<jobject>::JObjectWrapper;
@ -328,7 +328,6 @@ class JObjectWrapper<jtypeArray<T>> : public JObjectWrapper<jobject> {
private:
jtypeArray<T> self() const noexcept;
static std::string bareClassName();
};
template <class T>
@ -366,7 +365,8 @@ class PinnedPrimitiveArray;
#pragma push_macro("DECLARE_PRIMITIVE_ARRAY_UTILS")
#undef DECLARE_PRIMITIVE_ARRAY_UTILS
#define DECLARE_PRIMITIVE_ARRAY_UTILS(TYPE, DESC) \
#define DECLARE_PRIMITIVE_ARRAY_UTILS(TYPE, NAME, DESC) \
\
local_ref<j ## TYPE ## Array> make_ ## TYPE ## _array(jsize size); \
\
template<> class JObjectWrapper<j ## TYPE ## Array> : public JArray { \
@ -375,25 +375,30 @@ template<> class JObjectWrapper<j ## TYPE ## Array> : public JArray { \
\
using JArray::JArray; \
\
static local_ref<j ## TYPE ## Array> newArray(size_t count); \
\
j ## TYPE* getRegion(jsize start, jsize length, j ## TYPE* buf); \
std::unique_ptr<j ## TYPE[]> getRegion(jsize start, jsize length); \
void setRegion(jsize start, jsize length, j ## TYPE* buf); \
void setRegion(jsize start, jsize length, const j ## TYPE* buf); \
PinnedPrimitiveArray<j ## TYPE> pin(); \
\
private: \
j ## TYPE ## Array self() const noexcept { \
return static_cast<j ## TYPE ## Array>(this_); \
} \
} \
}; \
\
using JArray ## NAME = JObjectWrapper<j ## TYPE ## Array> \
DECLARE_PRIMITIVE_ARRAY_UTILS(boolean, "Z");
DECLARE_PRIMITIVE_ARRAY_UTILS(byte, "B");
DECLARE_PRIMITIVE_ARRAY_UTILS(char, "C");
DECLARE_PRIMITIVE_ARRAY_UTILS(short, "S");
DECLARE_PRIMITIVE_ARRAY_UTILS(int, "I");
DECLARE_PRIMITIVE_ARRAY_UTILS(long, "J");
DECLARE_PRIMITIVE_ARRAY_UTILS(float, "F");
DECLARE_PRIMITIVE_ARRAY_UTILS(double, "D");
DECLARE_PRIMITIVE_ARRAY_UTILS(boolean, Boolean, "Z");
DECLARE_PRIMITIVE_ARRAY_UTILS(byte, Byte, "B");
DECLARE_PRIMITIVE_ARRAY_UTILS(char, Char, "C");
DECLARE_PRIMITIVE_ARRAY_UTILS(short, Short, "S");
DECLARE_PRIMITIVE_ARRAY_UTILS(int, Int, "I");
DECLARE_PRIMITIVE_ARRAY_UTILS(long, Long, "J");
DECLARE_PRIMITIVE_ARRAY_UTILS(float, Float, "F");
DECLARE_PRIMITIVE_ARRAY_UTILS(double, Double, "D");
#pragma pop_macro("DECLARE_PRIMITIVE_ARRAY_UTILS")
@ -444,6 +449,16 @@ class PinnedPrimitiveArray {
};
namespace detail {
class BaseJavaClass {
public:
typedef _jobject _javaobject;
typedef _javaobject* javaobject;
};
}
// Together, these classes allow convenient use of any class with the fbjni
// helpers. To use:
//
@ -453,11 +468,11 @@ class PinnedPrimitiveArray {
//
// alias_ref<MyClass::javaobject> myClass = foo();
template <typename T>
template <typename T, typename Base = detail::BaseJavaClass>
class JavaClass {
public:
// JNI pattern for jobject assignable pointer
struct _javaobject : public _jobject {
struct _javaobject : public Base::_javaobject {
typedef T javaClass;
};
typedef _javaobject* javaobject;
@ -478,6 +493,13 @@ public:
std::remove_pointer<T>::type::javaClass::kJavaDescriptor;
using JObjectWrapper<jobject>::JObjectWrapper;
template<typename U>
JObjectWrapper(const JObjectWrapper<U>& w)
: JObjectWrapper<jobject>(w) {
static_assert(std::is_convertible<U, T>::value,
"U must be convertible to T");
}
};
}}

View File

@ -9,7 +9,7 @@
#include "Exceptions.h"
#include "CoreClasses.h"
#include "../ALog.h"
#include <jni/ALog.h>
#include <fb/assert.h>

View File

@ -17,13 +17,13 @@
namespace facebook {
namespace jni {
class BaseHybridClass {
namespace detail {
class BaseHybridClass : public BaseJavaClass {
public:
virtual ~BaseHybridClass() {}
};
namespace detail {
struct HybridData : public JavaClass<HybridData> {
constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridData;";
};
@ -83,6 +83,21 @@ struct Convert<const char*> {
}
};
// jboolean is an unsigned char, not a bool. Allow it to work either way.
template<>
struct Convert<bool> {
typedef jboolean jniType;
static bool fromJni(jniType t) {
return t;
}
static jniType toJniRet(bool t) {
return t;
}
static jniType toCall(bool t) {
return t;
}
};
// convert to alias_ref<T> from T
template <typename T>
struct Convert<alias_ref<T>> {
@ -145,17 +160,28 @@ struct jstring_holder {
operator jstring() { return s_.get(); }
};
}
template <typename T, typename Enabled = void>
struct HybridRoot {};
template <typename T>
class HybridClass : public BaseHybridClass
, public JavaClass<T> {
struct HybridRoot<T,
typename std::enable_if<!std::is_base_of<BaseHybridClass, T>::value>::type>
: public BaseHybridClass {};
}
template <typename T, typename Base = detail::BaseHybridClass>
class HybridClass : public Base
, public detail::HybridRoot<Base>
, public JavaClass<T, Base> {
public:
typedef detail::HybridData::javaobject jhybriddata;
typedef typename JavaClass<T>::javaobject jhybridobject;
typedef typename JavaClass<T, Base>::javaobject jhybridobject;
// I'm not sure why I need this, but I get errors without it.
using JavaClass<T>::javaClassStatic;
using JavaClass<T, Base>::javaClassStatic;
using JavaClass<T, Base>::javaClassLocal;
using JavaClass<T, Base>::javaobject;
typedef typename JavaClass<T, Base>::_javaobject _javaobject;
protected:
typedef HybridClass HybridBase;
@ -163,7 +189,7 @@ protected:
// This ensures that a C++ hybrid part cannot be created on its own
// by default. If a hybrid wants to enable this, it can provide its
// own public ctor, or change the accessibility of this to public.
HybridClass() = default;
using Base::Base;
static void registerHybrid(std::initializer_list<NativeMethod> methods) {
javaClassStatic()->registerNatives(methods);

View File

@ -153,15 +153,23 @@ inline local_ref<T*> JNonvirtualMethod<T*(Args...)>::operator()(
/// support for your user defined type.
template<typename T>
struct jtype_traits {
// The jni type signature (described at
// http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html).
static std::string descriptor() {
if (JObjectWrapper<T>::kJavaDescriptor != nullptr) {
return std::string{JObjectWrapper<T>::kJavaDescriptor};
};
return JObjectWrapper<T>::get_instantiated_java_descriptor();
static const auto descriptor = JObjectWrapper<T>::kJavaDescriptor != nullptr ?
std::string{JObjectWrapper<T>::kJavaDescriptor} :
JObjectWrapper<T>::get_instantiated_java_descriptor();
return descriptor;
}
static std::string array_descriptor() {
return '[' + std::string{JObjectWrapper<T>::kJavaDescriptor};
// The signature used for class lookups. See
// http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getName().
static std::string base_name() {
if (JObjectWrapper<T>::kJavaDescriptor != nullptr) {
std::string base_name = JObjectWrapper<T>::kJavaDescriptor;
return base_name.substr(1, base_name.size() - 2);
}
return JObjectWrapper<T>::get_instantiated_java_descriptor();
}
};
@ -172,10 +180,12 @@ struct jtype_traits {
template<> \
struct jtype_traits<TYPE> { \
static std::string descriptor() { return std::string{#DSC}; } \
static std::string base_name() { return descriptor(); } \
}; \
template<> \
struct jtype_traits<TYPE ## Array> { \
static std::string descriptor() { return std::string{"[" #DSC}; } \
static std::string base_name() { return descriptor(); } \
};
// There is no voidArray, handle that without the macro.

View File

@ -129,6 +129,12 @@ inline base_owned_ref<T, Alloc>::base_owned_ref(
: object_{Alloc{}.newReference(other.getPlainJniReference())}
{}
template<typename T, typename Alloc>
template<typename U>
inline base_owned_ref<T, Alloc>::base_owned_ref(const base_owned_ref<U, Alloc>& other)
: object_{Alloc{}.newReference(other.getPlainJniReference())}
{}
template<typename T, typename Alloc>
inline facebook::jni::base_owned_ref<T, Alloc>::base_owned_ref(
T reference) noexcept
@ -148,6 +154,17 @@ inline base_owned_ref<T, Alloc>::base_owned_ref(
other.object_.set(nullptr);
}
template<typename T, typename Alloc>
template<typename U>
base_owned_ref<T, Alloc>::base_owned_ref(base_owned_ref<U, Alloc>&& other) noexcept
: object_{other.object_} {
internal::dbglog("New move from ref=%p other=%p", other.getPlainJniReference(), &other);
internal::dbglog("New move to ref=%p this=%p", getPlainJniReference(), this);
// JObjectWrapper is a simple type and does not support move semantics so we explicitly
// clear other
other.object_.set(nullptr);
}
template<typename T, typename Alloc>
inline base_owned_ref<T, Alloc>::~base_owned_ref() noexcept {
reset();

View File

@ -238,9 +238,13 @@ class base_owned_ref {
/// Copy constructor (note creates a new reference)
base_owned_ref(const base_owned_ref& other);
template<typename U>
base_owned_ref(const base_owned_ref<U, Alloc>& other);
/// Transfers ownership of an underlying reference from one unique reference to another
base_owned_ref(base_owned_ref&& other) noexcept;
template<typename U>
base_owned_ref(base_owned_ref<U, Alloc>&& other) noexcept;
/// The delete the underlying reference if applicable
~base_owned_ref() noexcept;
@ -259,6 +263,9 @@ class base_owned_ref {
friend T jni::getPlainJniReference<>(const base_owned_ref& ref);
template<typename U, typename UAlloc>
friend class base_owned_ref;
};
@ -279,6 +286,8 @@ class weak_ref : public base_owned_ref<T, WeakGlobalReferenceAllocator> {
using PlainJniType = T;
using Allocator = WeakGlobalReferenceAllocator;
// This inherits non-default, non-copy, non-move ctors.
using base_owned_ref<T, Allocator>::base_owned_ref;
/// Create a null reference
constexpr weak_ref() noexcept
@ -343,10 +352,11 @@ class basic_strong_ref : public base_owned_ref<T, Alloc> {
using PlainJniType = T;
using Allocator = Alloc;
// This inherits non-default, non-copy, non-move ctors.
using base_owned_ref<T, Alloc>::base_owned_ref;
using base_owned_ref<T, Alloc>::release;
using base_owned_ref<T, Alloc>::reset;
/// Create a null reference
constexpr basic_strong_ref() noexcept
: base_owned_ref<T, Alloc>{} {}
@ -363,7 +373,6 @@ class basic_strong_ref : public base_owned_ref<T, Alloc> {
basic_strong_ref(basic_strong_ref&& other) noexcept
: base_owned_ref<T, Alloc>{std::move(other)} {}
/// Assignment operator (note creates a new reference)
basic_strong_ref& operator=(const basic_strong_ref& other);

View File

@ -32,6 +32,8 @@ struct Convert<
// There is no automatic return conversion for objects.
};
// registration wrapper for legacy JNI-style functions
template<typename F, F func, typename C, typename... Args>
inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(JNIEnv*, C, Args... args)) {
struct funcWrapper {
@ -50,25 +52,6 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(JNIEnv*, C, Args...
return reinterpret_cast<NativeMethodWrapper*>(&(funcWrapper::call));
}
template<typename F, F func, typename C, typename... Args>
inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(C, Args... args)) {
struct funcWrapper {
static void call(JNIEnv* env, jobject obj, Args... args) {
// Note that if func was declared noexcept, then both gcc and clang are smart
// enough to elide the try/catch.
try {
(void) env;
(*func)(static_cast<C>(obj), args...);
} catch (...) {
translatePendingCppExceptionToJavaException();
}
}
};
// This intentionally erases the real type; JNI will do it anyway
return reinterpret_cast<NativeMethodWrapper*>(&(funcWrapper::call));
}
template<typename F, F func, typename C, typename R, typename... Args>
inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(JNIEnv*, C, Args... args)) {
struct funcWrapper {
@ -86,6 +69,8 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(JNIEnv*, C, Args... arg
return reinterpret_cast<NativeMethodWrapper*>(&(funcWrapper::call));
}
// registration wrappers for functions, with autoconversion of arguments.
template<typename F, F func, typename C, typename... Args>
inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(alias_ref<C>, Args... args)) {
struct funcWrapper {
@ -124,6 +109,8 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(alias_ref<C>, Args... a
return reinterpret_cast<NativeMethodWrapper*>(&(funcWrapper::call));
}
// registration wrappers for non-static methods, with autoconvertion of arguments.
template<typename M, M method, typename C, typename... Args>
inline NativeMethodWrapper* exceptionWrapJNIMethod(void (C::*method0)(Args... args)) {
struct funcWrapper {