From f4b76a36887fa83ca38a7648f0bb03bf438cf4a9 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Fri, 15 Jun 2018 11:53:38 +0100 Subject: [PATCH] commit changes in fbjni --- libs/fbjni/build.gradle | 2 +- .../src/main/cpp/include/fb/fbjni/Hybrid.h | 426 ++++++++---------- libs/fbjni/src/main/cpp/jni/Hybrid.cpp | 2 +- 3 files changed, 188 insertions(+), 242 deletions(-) diff --git a/libs/fbjni/build.gradle b/libs/fbjni/build.gradle index f4aa91810..812e34e27 100644 --- a/libs/fbjni/build.gradle +++ b/libs/fbjni/build.gradle @@ -9,7 +9,7 @@ android { targetSdkVersion rootProject.targetSdkVersion ndk { - abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' + abiFilters 'arm64-v8a', 'x86' } externalNativeBuild { diff --git a/libs/fbjni/src/main/cpp/include/fb/fbjni/Hybrid.h b/libs/fbjni/src/main/cpp/include/fb/fbjni/Hybrid.h index e8b4d4e92..f020826cb 100644 --- a/libs/fbjni/src/main/cpp/include/fb/fbjni/Hybrid.h +++ b/libs/fbjni/src/main/cpp/include/fb/fbjni/Hybrid.h @@ -5,281 +5,227 @@ * LICENSE file in the root directory of this source tree. */ +#pragma once - #pragma once +#include +#include - #include - #include +#include +#include - #include "CoreClasses.h" +#include "CoreClasses.h" - namespace facebook { - namespace jni { +namespace facebook { +namespace jni { - namespace detail { +namespace detail { - class BaseHybridClass { - public: - virtual ~BaseHybridClass() {} - }; +class BaseHybridClass { +public: + virtual ~BaseHybridClass() {} +}; - struct HybridData : public JavaClass { - constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridData;"; - static local_ref create(); - }; +struct FBEXPORT HybridData : public JavaClass { + constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridData;"; + void setNativePointer(std::unique_ptr new_value); + BaseHybridClass* getNativePointer(); + static local_ref create(); +}; - class HybridDestructor : public JavaClass { - public: - static auto constexpr kJavaDescriptor = "Lcom/facebook/jni/HybridData$Destructor;"; +template +struct HybridTraits { + // This static assert should actually always fail if we don't use one of the + // specializations below. + static_assert( + std::is_base_of::value || + std::is_base_of::value, + "The base of a HybridClass must be either another HybridClass or derived from JObject."); +}; - detail::BaseHybridClass* getNativePointer(); +template <> +struct HybridTraits { + using CxxBase = BaseHybridClass; + using JavaBase = JObject; +}; - void setNativePointer(std::unique_ptr new_value); - }; +template +struct HybridTraits< + Base, + typename std::enable_if::value>::type> { + using CxxBase = Base; + using JavaBase = typename Base::JavaPart; +}; - template - detail::BaseHybridClass* getNativePointer(T t) { - return getHolder(t)->getNativePointer(); - } +template +struct HybridTraits< + Base, + typename std::enable_if::value>::type> { + using CxxBase = BaseHybridClass; + using JavaBase = Base; +}; - template - void setNativePointer(T t, std::unique_ptr new_value) { - getHolder(t)->setNativePointer(std::move(new_value)); - } +// convert to HybridClass* from jhybridobject +template +struct FBEXPORT Convert< + T, typename std::enable_if< + std::is_base_of::type>::value>::type> { + typedef typename std::remove_pointer::type::jhybridobject jniType; + static T fromJni(jniType t) { + if (t == nullptr) { + return nullptr; + } + return wrap_alias(t)->cthis(); + } + // There is no automatic return conversion for objects. +}; - template - local_ref getHolder(T t) { - static auto holderField = t->getClass()->template getField("mDestructor"); - return t->getFieldValue(holderField); - } - - // JavaClass for HybridClassBase - struct HybridClassBase : public JavaClass { - constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridClassBase;"; - - static bool isHybridClassBase(alias_ref jclass) { - return HybridClassBase::javaClassStatic()->isAssignableFrom(jclass); - } - }; - - template - struct HybridTraits { - // This static assert should actually always fail if we don't use one of the - // specializations below. - static_assert( - std::is_base_of::value || - std::is_base_of::value, - "The base of a HybridClass must be either another HybridClass or derived from JObject."); - }; - - template <> - struct HybridTraits { - using CxxBase = BaseHybridClass; - using JavaBase = JObject; - }; - - template - struct HybridTraits< - Base, - typename std::enable_if::value>::type> { - using CxxBase = Base; - using JavaBase = typename Base::JavaPart; - }; - - template - struct HybridTraits< - Base, - typename std::enable_if::value>::type> { - using CxxBase = BaseHybridClass; - using JavaBase = Base; - }; - - // convert to HybridClass* from jhybridobject - template - struct Convert< - T, typename std::enable_if< - std::is_base_of::type>::value>::type> { - typedef typename std::remove_pointer::type::jhybridobject jniType; - static T fromJni(jniType t) { - if (t == nullptr) { - return nullptr; - } - return wrap_alias(t)->cthis(); - } - // There is no automatic return conversion for objects. - }; - - template - struct RefReprType::value, void>::type> { - static_assert(std::is_same::value, - "HybridFoo (where HybridFoo derives from HybridClass) is not supported in this context. " - "For an xxx_ref, you may want: xxx_ref or HybridFoo*."); - using Repr = T; - }; +template +struct RefReprType::value, void>::type> { + static_assert(std::is_same::value, + "HybridFoo (where HybridFoo derives from HybridClass) is not supported in this context. " + "For an xxx_ref, you may want: xxx_ref or HybridFoo*."); + using Repr = T; +}; - } +} - template - class HybridClass : public detail::HybridTraits::CxxBase { - public: - struct JavaPart : JavaClass::JavaBase> { - // At this point, T is incomplete, and so we cannot access - // T::kJavaDescriptor directly. jtype_traits support this escape hatch for - // such a case. - static constexpr const char* kJavaDescriptor = nullptr; - static std::string get_instantiated_java_descriptor(); - static std::string get_instantiated_base_name(); +template +class FBEXPORT HybridClass : public detail::HybridTraits::CxxBase { +public: + struct JavaPart : JavaClass::JavaBase> { + // At this point, T is incomplete, and so we cannot access + // T::kJavaDescriptor directly. jtype_traits support this escape hatch for + // such a case. + static constexpr const char* kJavaDescriptor = nullptr; + static std::string get_instantiated_java_descriptor(); + static std::string get_instantiated_base_name(); - using HybridType = T; + using HybridType = T; - // This will reach into the java object and extract the C++ instance from - // the mHybridData and return it. - T* cthis(); + // This will reach into the java object and extract the C++ instance from + // the mHybridData and return it. + T* cthis(); - friend class HybridClass; - friend T; - }; + friend class HybridClass; + }; - using jhybridobject = typename JavaPart::javaobject; - using javaobject = typename JavaPart::javaobject; - typedef detail::HybridData::javaobject jhybriddata; + using jhybridobject = typename JavaPart::javaobject; + using javaobject = typename JavaPart::javaobject; + typedef detail::HybridData::javaobject jhybriddata; - static alias_ref javaClassStatic() { - return JavaPart::javaClassStatic(); - } + static alias_ref javaClassStatic() { + return JavaPart::javaClassStatic(); + } - static local_ref javaClassLocal() { - std::string className(T::kJavaDescriptor + 1, strlen(T::kJavaDescriptor) - 2); - return findClassLocal(className.c_str()); - } + static local_ref javaClassLocal() { + std::string className(T::kJavaDescriptor + 1, strlen(T::kJavaDescriptor) - 2); + return findClassLocal(className.c_str()); + } - protected: - typedef HybridClass HybridBase; +protected: + typedef HybridClass HybridBase; - // 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. - using detail::HybridTraits::CxxBase::CxxBase; + // 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. + using detail::HybridTraits::CxxBase::CxxBase; - static void registerHybrid(std::initializer_list methods) { - javaClassStatic()->registerNatives(methods); - } + static void registerHybrid(std::initializer_list methods) { + javaClassStatic()->registerNatives(methods); + } - static local_ref makeHybridData(std::unique_ptr cxxPart) { - auto hybridData = detail::HybridData::create(); - setNativePointer(hybridData, std::move(cxxPart)); - return hybridData; - } + static local_ref makeHybridData(std::unique_ptr cxxPart) { + auto hybridData = detail::HybridData::create(); + hybridData->setNativePointer(std::move(cxxPart)); + return hybridData; + } - template - static local_ref makeCxxInstance(Args&&... args) { - return makeHybridData(std::unique_ptr(new T(std::forward(args)...))); - } + template + static local_ref makeCxxInstance(Args&&... args) { + return makeHybridData(std::unique_ptr(new T(std::forward(args)...))); + } - template - static void setCxxInstance(alias_ref o, Args&&... args) { - setNativePointer(o, std::unique_ptr(new T(std::forward(args)...))); - } - - public: - // Factory method for creating a hybrid object where the arguments - // are used to initialize the C++ part directly without passing them - // through java. This method requires the Java part to have a ctor - // which takes a HybridData, and for the C++ part to have a ctor - // compatible with the arguments passed here. For safety, the ctor - // can be private, and the hybrid declared a friend of its base, so - // the hybrid can only be created from here. - // - // Exception behavior: This can throw an exception if creating the - // C++ object fails, or any JNI methods throw. - template - static local_ref newObjectCxxArgs(Args&&... args) { - static bool isHybrid = detail::HybridClassBase::isHybridClassBase(javaClassStatic()); - auto cxxPart = std::unique_ptr(new T(std::forward(args)...)); - - local_ref result; - if (isHybrid) { - result = JavaPart::newInstance(); - setNativePointer(result, std::move(cxxPart)); - } - else { - auto hybridData = makeHybridData(std::move(cxxPart)); - result = JavaPart::newInstance(hybridData); - } - - return result; - } +public: + // Factory method for creating a hybrid object where the arguments + // are used to initialize the C++ part directly without passing them + // through java. This method requires the Java part to have a ctor + // which takes a HybridData, and for the C++ part to have a ctor + // compatible with the arguments passed here. For safety, the ctor + // can be private, and the hybrid declared a friend of its base, so + // the hybrid can only be created from here. + // + // Exception behavior: This can throw an exception if creating the + // C++ object fails, or any JNI methods throw. + template + static local_ref newObjectCxxArgs(Args&&... args) { + auto hybridData = makeCxxInstance(std::forward(args)...); + return JavaPart::newInstance(hybridData); + } // TODO? Create reusable interface for Allocatable classes and use it to - // strengthen type-checking (and possibly provide a default - // implementation of allocate().) - template - static local_ref allocateWithCxxArgs(Args&&... args) { - auto hybridData = makeCxxInstance(std::forward(args)...); - static auto allocateMethod = - javaClassStatic()->template getStaticMethod("allocate"); - return allocateMethod(javaClassStatic(), hybridData.get()); - } + // strengthen type-checking (and possibly provide a default + // implementation of allocate().) + template + static local_ref allocateWithCxxArgs(Args&&... args) { + auto hybridData = makeCxxInstance(std::forward(args)...); + static auto allocateMethod = + javaClassStatic()->template getStaticMethod("allocate"); + return allocateMethod(javaClassStatic(), hybridData.get()); + } - // Factory method for creating a hybrid object where the arguments - // are passed to the java ctor. - template - static local_ref newObjectJavaArgs(Args&&... args) { - return JavaPart::newInstance(std::move(args)...); - } + // Factory method for creating a hybrid object where the arguments + // are passed to the java ctor. + template + static local_ref newObjectJavaArgs(Args&&... args) { + return JavaPart::newInstance(std::move(args)...); + } - // If a hybrid class throws an exception which derives from - // std::exception, it will be passed to mapException on the hybrid - // class, or nearest ancestor. This allows boilerplate exception - // translation code (for example, calling throwNewJavaException on a - // particular java class) to be hoisted to a common function. If - // mapException returns, then the std::exception will be translated - // to Java. - static void mapException(const std::exception& ex) {} - }; + // If a hybrid class throws an exception which derives from + // std::exception, it will be passed to mapException on the hybrid + // class, or nearest ancestor. This allows boilerplate exception + // translation code (for example, calling throwNewJavaException on a + // particular java class) to be hoisted to a common function. If + // mapException returns, then the std::exception will be translated + // to Java. + static void mapException(const std::exception& ex) {} +}; - template - inline T* HybridClass::JavaPart::cthis() { - detail::BaseHybridClass* result = 0; - static bool isHybrid = detail::HybridClassBase::isHybridClassBase(this->getClass()); - if (isHybrid) { - result = getNativePointer(this); - } else { - static auto field = - HybridClass::JavaPart::javaClassStatic()->template getField("mHybridData"); - auto hybridData = this->getFieldValue(field); - if (!hybridData) { - throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); - } +template +inline T* HybridClass::JavaPart::cthis() { + static auto field = + HybridClass::JavaPart::javaClassStatic()->template getField("mHybridData"); + auto hybridData = this->getFieldValue(field); + if (!hybridData) { + throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); + } + // I'd like to use dynamic_cast here, but -fno-rtti is the default. + T* value = static_cast(hybridData->getNativePointer()); + // This would require some serious programmer error. + FBASSERTMSGF(value != 0, "Incorrect C++ type in hybrid field"); + return value; +}; - result = getNativePointer(hybridData); - } +template +/* static */ inline std::string HybridClass::JavaPart::get_instantiated_java_descriptor() { + return T::kJavaDescriptor; +} - // I'd like to use dynamic_cast here, but -fno-rtti is the default. - return static_cast(result); - }; +template +/* static */ inline std::string HybridClass::JavaPart::get_instantiated_base_name() { + auto name = get_instantiated_java_descriptor(); + return name.substr(1, name.size() - 2); +} - template - /* static */ inline std::string HybridClass::JavaPart::get_instantiated_java_descriptor() { - return T::kJavaDescriptor; - } +// Given a *_ref object which refers to a hybrid class, this will reach inside +// of it, find the mHybridData, extract the C++ instance pointer, cast it to +// the appropriate type, and return it. +template +inline auto cthis(T jthis) -> decltype(jthis->cthis()) { + return jthis->cthis(); +} - template - /* static */ inline std::string HybridClass::JavaPart::get_instantiated_base_name() { - auto name = get_instantiated_java_descriptor(); - return name.substr(1, name.size() - 2); - } +void HybridDataOnLoad(); - // Given a *_ref object which refers to a hybrid class, this will reach inside - // of it, find the mHybridData, extract the C++ instance pointer, cast it to - // the appropriate type, and return it. - template - inline auto cthis(T jthis) -> decltype(jthis->cthis()) { - return jthis->cthis(); - } - - void HybridDataOnLoad(); - - } - } +} +} diff --git a/libs/fbjni/src/main/cpp/jni/Hybrid.cpp b/libs/fbjni/src/main/cpp/jni/Hybrid.cpp index 049e4a296..523e2fd27 100644 --- a/libs/fbjni/src/main/cpp/jni/Hybrid.cpp +++ b/libs/fbjni/src/main/cpp/jni/Hybrid.cpp @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ - #include "fb/fbjni.h" +#include "fb/fbjni.h" namespace facebook {