Reactnative 4Android Source Code Analysis II: "The implementation of the JNI smart pointer"

Source: Internet
Author: User

Wen/tamic
http://blog.csdn.net/sk719887916/article/details/53462268

Review

The previous article introduced the "Reactnative4android Source analysis 2:jni Smart pointer Introduction" JNI Smart pointer and wrapper class, the following will be the implementation of their specific analysis, and answer the questions raised in the previous article

The previous article reviews the 3 types of Java object Reference object Jobject in JNI. Smart pointers naturally also have the following types:

Global_ref

Global pointers correspond to jobject global references, using scenarios including global variables, member variables, and so on. The jobject in these scenarios should not be released from native when returned to the JVM, so use Global_ref for the package.

Local_ref

Local pointers correspond to Jobject local references, and the usage scenarios include local variables, function return values, and so on. When Local_ref leaves its scope, it releases its own reference to Jobject, which is called Deletelocalref in the destructor.

Weak_ref

The weak pointer corresponds to the jobject weak global reference and is not actually used in the current version of the RN code.

Alias_ref

An alias pointer that does not manage the life cycle of the Jobject being held. That is, when you construct and refactor an alias smart pointer object, you do not create and destroy JNI operations on the jobject that are held. The purpose of this pointer is only to provide the ability to invoke the wrapper object method, the life cycle of the jobject is managed by another smart pointer or directly by the JVM and is guaranteed to be effective, and the pointer itself does not manage it extra.

None of the above smart pointers provide a reference counting function, but instead, the pointer is converted by exchanging managed objects between smart pointers. The class diagram for the smart pointer is shown below, and its code is in reactandroid/src/main/jni/first-party/fb/include/fb/fbjni/references.h:

Smart pointer class diagram

Smart pointers

As you can see, because of functional differences, the alias_ref alias pointer is a separate class, and the rest of the smart pointers have a common parent class base_owned_ref . The most need to focus on the storage of smart pointers, Base_owned_ref and Alias_ref have the same member variables:

Detail::reprstorage Storage_;

**storage**_ is used to store created wrapper objects. This side of the design is quite ingenious, using the type extraction technique in C + + to associate wrapper objects with Jobject, and jobject (JNI layer), Javaobject (RN layer), traits, The wrapper object (RN layer) is unified in the memory space. First look at the implementation of Reprstorage:

template <typename Repr>struct ReprStorage {  explicit ReprStorage(JniType<Repr> obj) noexcept;  void set(JniType<Repr> obj) noexcept;  Repr& get() noexcept;  const Repr& get() const noexcept;  JniType<Repr> jobj() const noexcept; private:  using Storage = typename std::aligned_storage<sizeof(JObjectBase), alignof(JObjectBase)>::type;  Storage storage_;};template <typename Repr>void ReprStorage<Repr>::set(JniType<Repr> obj) noexcept {  new (&storage_) Repr;  ReprAccess<Repr>::set(get(), obj);}template <typename Repr>Repr& ReprStorage<Repr>::get() noexcept {  return *reinterpret_cast<Repr*>(&storage_);}

Irrelevant code has been omitted. ReprStorageUse the private variable Storage_ as the storage space, the size of the Jobjectbase class. As can be seen from the set and get functions, the allocation of the Storage_ memory space is delay to the set value, and the Storage_ memory space pointer is converted to the repr type through the reinterpret_cast type. The reprstorage template parameter repr is the type of stored wrapper class, in the example used in the previous chapter, which is MyClass:

struct Myclass:public Javaclass

the inheritance relationship between wrapper class is as follows :


Wrapper class inheritance Relationship

Jobjectbase

Jobjectbase is the root parent of wrapper class, and there is obviously a problem: why can I use the memory space of the parent size to store arbitrary subclass objects? After completing the discussion of the inheritance relationship, review the question. The customjavaclass in the figure is a custom wrapper class that inherits from a template instance of Javaclass. All Java classes (except the object class) native mirror wrapper class need to inherit from a template instance of Javaclass. Javaclass up to two bridges: the currently defined wrapper class and the bridge that corresponds to the wrapper class of the Java class's parent class; The current defined wrapper class and the corresponding Java object JNI The Jobject Bridge. It has three template parameters, the following is its class declaration, whose code is located in Reactandroid/src/main/jni/first-party/fb/include/fb/fbjni/coreclasses.h:

template <typename T, typename Base = JObject, typename JType = void>class FBEXPORT JavaClass : public Base {public:  static alias_ref<JClass> javaClassStatic();  static local_ref<JClass> javaClassLocal();protected:  /// Allocates a new object and invokes the specified constructor  /// Like JClass‘s getConstructor, this function can only check at runtime if  /// the class actually has a constructor that accepts the corresponding types.  /// While a JavaClass-type can expose this function directly, it is recommended  /// to instead to use this to explicitly only expose those constructors that  /// the Java class actually has (i.e. with static create() functions).  template<typename... Args>  static local_ref<T> newInstance(Args... args) {return detail::newInstance<T>(args...);  }  javaobject self() const noexcept;}

Irrelevant code has been omitted.

the first template parameter is the type of the sub-wrapper class .
This template instance of Javaclass, as the parent class of this wrapper class, provides the factory method to create the wrapper class object and the ability to associate with the corresponding jobject, so you need to get the type of the subclass.

The Second template parameter is the parent class of the Javaclass template instance.
Its default type is Jobject, which represents the wrapper class of the Java.lang.Object classes, and is the only wrapper object that does not need to inherit from Javaclass. Jobject provides access encapsulation methods for Java objects such as class, Field, method, and so on, wrapper class obtains the ability to invoke Java method by inheriting the relationship. If wrapper class does not provide the ability to invoke the Java class parent method, the second template parameter remains the default value Jobject, otherwise the second template parameter is the wrapper class of the Java class parent class, as the example is provided in the previous chapter. Because Javaclass helps build the inheritance chain, wrapper class has the ability to provide native mirroring methods for the parent Java class.

The third template parameter is the type of JNI jobject that defines the wrapper class corresponding to the Java object

Javaclass will establish a binding relationship between wrapper class and Jobject. Depending on the specific type of jobject, there are two cases, if the pre-defined Jobject types are JNI, such as Jclass, Jthrowable, Jarray, jstring, and so on, the third template parameter is them, and the RN has pre-defined their wrapper Class For example:

class FBEXPORT JString : public JavaClass<JString, JObject, jstring> {}

Another case is a non-predefined type, that is, the generic type Jobject (Jclass, jstring, and so on, which is also its subclass), then the third parameter should be the default value void. That is, the specific subclass of Jobject is not specified by the template parameter, but rather the extension subclass defined by the wrapper class inner nesting.

Before you browse jobject internal definitions, review the storage issues that you just made. Since the memory space of sizeof (jobjectbase) can correctly place an instance of any wrapper class subclass, it means that the subclass occupies the same amount of memory as the root class jobjectbase. For a C + + class, the size of the object is the sum of the size of all non-static member variables (with memory alignment in mind), which constrains the wrapper class to declare any non-static member variables as subclasses. To keep size consistent with the root parent class jobjectbase. Considering the design purpose of wrapper class, it is only the class of Java class in native space and the interface wrapper class, the business logic should be implemented by the caller, wrapper class itself should be stateless, so wrapper is not allowed class defines a non-static member variable to be reasonable.

Smart pointers are stored in an wrapper class instance, wrapper class is stored in the Jobject, from the above analysis can be known that the stored Jobject member variables can only be hosted by the root parent class jobjectbase. The following is the class definition for Jobjectbase, which is located in reactandroid/src/main/jni/first-party/fb/include/fb/fbjni/references-forward.h:

struct JObjectBase {  jobject get() const noexcept;  void set(jobject reference) noexcept;  jobject this_;};

Jobjectbase is a simple bean class, and the only member variable is jobject, which is the only member variable of all wrapper class. In the Javaclass template class, in order to implement the Jobject and wrapper class of the association, the Jobject did an internal extension definition. To understand it, first review the original definition of jobject in jni.h :

class _jobject {};typedef _jobject*   jobject;class _jstring : public _jobject {};

So, Jobject is a pointer to a Java object in the JVM memory object, for **dexposed** a hot fix framework like this, is to use these pointers to modify the Java objects model to change the properties of Java method to implement hooks. The definition here is an empty class, just to define the pointer syntax to refer to memory objects in JNI, does not mean that the Java memory object is really an empty object and is really defined as a platform-relative within the JVM, without the need to expose implementation details to JNI. _jobject In Javaclass, the extension definition for Jobject is javaobject type as follows:

  template <typename T, typename Base = Jobject, typename Jtype = Void>class Fbexport javaclass:public Ba Se {using Jobjtype = TypeName detail::jtypefor<t, Base, jtype>;p ublic:using _javaobject = TypeName Jobjtype::_ja  Vaobject; Using Javaobject = typename jobjtype::javaobject;}; Namespace Detail {Template <typename, TypeName Base, TypeName jtype>struct jtypefor {static_assert (std::is_base_  Of<std::remove_pointer<jobject>::type,typename std::remove_pointer<jtype>::type >::value, "");  Using _javaobject = TypeName std::remove_pointer<jtype>::type; Using Javaobject = Jtype;}; Template <typename T, typename base>struct jtypefor<t, Base, void> {//JNI pattern for Jobject assignable PO Inter struct _javaobject:base::_javaobject {//This allows us-to-map back-to-the-defining type (in Reprtype, for//Exa  mple). typedef T JNIREFREPR;  }; Using Javaobject = _javaobject*;};}  

In Javaclass, the jobject extension is defined as javaobject. Javaobject is a member pointer type of TypeName Jobjtype::javaobject, which is a template instance type of Jtypefor. In the example code of MyClass, for example, the parent class Javaclass received three template parameters of Myclass,jobject,void,jtypefor Three template parameters are also in turn, because the third parameter is void, it will use the above code in the Jtypefor

struct JTypeFor<MyClass, JObject, void> {  struct _javaobject :  JObject::_javaobject { typedef MyClass JniRefRepr;  };  using javaobject = _javaobject*;};}

You can see that _javaobject inherits from Jobject:: _javaobject, which is defined as follows:

 typedef _jobject _javaobject; typedef _javaobject* javaobject;

Jobject::_javaobject is the _jobject type in jni.h, so _javaobject inheritance extension of _jobject in MyClass, just adds a nested class member type JNIREFREPR, to point to the current _ Javaobject corresponds to the wrapper class type, which is called C + + type extraction technology. Because _jobject is used to point to Java memory objects, it cannot be extended in a way that adds member variables after inheritance, otherwise it destroys the memory object, and the member type belongs to the class definition and does not occupy the space of the object. In addition, Javaobject is a pointer to _javaobject , and Jobject is a pointer to _jobject.

Question Answer

Now to answer the three questions in the previous chapter:

What is the relationship between Javaobject and Jobject?

The two are essentially the same, all of which refer to the JNI reference to the Java memory object, the difference being that Javaobject is the Jobject inheritance extension, and the inherited Javaobject has a class member type variable that points to the corresponding wrapper class, making the two relate to each other. From memory, sizeof (Jobjectbase) ==sizeof (arbitrary wrapper Class) ==sizeof (Jobject) ==sizeof (javaobject), achieved organic unification.

Why can the template parameters of a smart pointer accept multiple types?

In the example above, local_ref\ and local_ref\ pass different template parameters, which are very significant from the syntax, but when implemented internally, type extraction is performed. That is, regardless of the type of transmission, the corresponding Reprtype (wrapper class type), Jnitype (javaobject type) will be extracted. The Javaobject class is the member type of the wrapper class, so the type of the corresponding Javaobject reference can be obtained from the wrapper class; The Javaobject class is of type wrapper, Therefore, the type of the corresponding wrapper class can be obtained from the javaobject industry. Two tools are available in the framework for type extraction and conversion:

// Given T, either a jobject-like type or a JavaClass-derived type, ReprType<T>// is the corresponding JavaClass-derived type and JniType<T> is the// jobject-like type.template <typename T>using ReprType = typename detail::RefReprType<T>::type;template <typename T>using JniType = typename detail::JavaObjectType<T>::type;

Reprtype is used to derive the wrapper class type from the template parameters, Jnitype is used to obtain the Javaobject type from the template parameters. Through such a mechanism, two types get through each other, so no matter what template parameters are passed, smart pointers can store the corresponding types correctly wrapper class .

What is the role of template parameters?

From the above you can see that the template parameter of the smart pointer is used to get the type of the stored wrapper class. For Local_ref and Global_ref, because they are strong references, they can be used to directly invoke the methods provided by the stored wrapper class, so their implementation template class Basic_strong_ref in Base_owned_ Based on the storage functionality provided by ref, the inheritance extension provides an overload of the pointer operator to forward access to the smart pointer to the wrapper object with the following code:

template<typename T, typename Alloc>inline auto basic_strong_ref<T, Alloc>::operator->() noexcept -> Repr* {return &storage_.get();}template<typename T, typename Alloc>inline auto basic_strong_ref<T, Alloc>::operator->() const noexcept -> const Repr* {return &storage_.get();}

In the overloaded implementation, the wrapper class instance obtained from the Storage_ is returned. For template parameter alloc, it is the type of allocator, which encapsulates the operation of creating and destroying Jobject, which is called by the smart Pointer during construction and destruction to achieve jobject lifecycle management.

Summarize

To summarize, this article briefly describes the backbone implementation of wrapper class and smart pointers. The wrapper class extends Jobject to Javaobject, makes the types associated with each other, constructs an inheritance chain, and decomposes the reflection calls on Java method and the inheritance of the Java class itself in different nodes of the link. The smart pointer is responsible for storing the jobject to the correct wrapper instance through the type extraction, providing the image method externally, and combining the construction and destructor to automate the life cycle management of the jobject.

Original: http://blog.csdn.net/eewolf/article/details/53307603

Reactnative 4Android Source Code Analysis II: "The implementation of the JNI smart pointer"

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.