Reputation: 45
I saw the code of jni.h
here :
http://xdprof.sourceforge.net/doxygen/jni_8h-source.html
and i want to know what is this:
class _jobject {};
00053 class _jclass : public _jobject {};
00054 class _jthrowable : public _jobject {};
00055 class _jstring : public _jobject {};
00056 class _jarray : public _jobject {};
00057 class _jbooleanArray : public _jarray {};
00058 class _jbyteArray : public _jarray {};
00059 class _jcharArray : public _jarray {};
00060 class _jshortArray : public _jarray {};
00061 class _jintArray : public _jarray {};
00062 class _jlongArray : public _jarray {};
00063 class _jfloatArray : public _jarray {};
00064 class _jdoubleArray : public _jarray {};
00065 class _jobjectArray : public _jarray {};
What is the relation for example between _jobject
empty class and Object
class - "Object.h/Object.cpp
" (internally in JVM) and why these classes are empty?
Upvotes: 0
Views: 206
Reputation: 98515
These classes are needed only to maintain hierarchy among corresponding JNI types:
jobject <- jarray <- jintArray etc.
So that jarray
can be used, for example, in a function that accepts jobject
.
The contents of the classes does not matter. JNI types are meant to be opaque for the application. There is no direct relation between JNI types and Java classes. This relation is hidden inside JVM code, i.e. if some JNI function expects jstring
argument, JVM explicitly treats that argument as a handle to java.lang.String
instance. E.g. from HotSpot sources:
JNI_QUICK_ENTRY(jsize, jni_GetStringLength(JNIEnv *env, jstring string))
...
oop s = JNIHandles::resolve_non_null(string);
if (java_lang_String::value(s) != NULL) { <-- explicitly cast a handle
ret = java_lang_String::length(s);
}
The type safety of such operations may or may not be enforced in runtime depending on JVM implementation. E.g. HotSpot can simply crash if you pass some crafted jstring
argument which is not actually a handle to java.lang.String
object.
EDIT
jstring
is a pointer to a pointer to a Java String instance (note double indirection). JVM does not access the value of class _jstring
but rather treats it as a pointer to the actual instance (see the above example).
java.lang.String JNIHandleBlock jstring string
------------------ ----------------------- -----------------
| 0: (header) |<---\ | oop[0] | /---| class _jclass * |
| 8: (class ptr) | \---| oop[1] <------------------/ -----------------
| 12: char[] value | | ... |
| 16: int hash | | oop[31] |
| 24: (padding) | | |
------------------ | int _top |
| JNIHandleBlock* _next |
| ... |
-----------------------
When working with jstring
, HotSpot JVM first resolves a handle to an oop
(ordinary object pointer):
oop s = JNIHandles::resolve_non_null(string);
// This is effectively the same as
// oop s = *(oop*)string;
Then to read a field of an oop, JVM uses raw pointer arithmetic (assuming it knows that the field value
has the offset 12 from the beginning of java.lang.String instance):
java_lang_String::value(s)
// Effectively the same as
// s->obj_field(12)
// which is expanded to something like
// *(oop*)((intptr_t)s + 12)
Other JVM implementations may treat class _jstring
differently. The idea is to make JNI types opaque so that different JVMs may implement JNI handles in their own way without need to recompile the code that uses those handles. That's why the contents of the classes does not matter - this is just the declaration, not the actual definition of the types.
Upvotes: 2
Reputation: 58467
This may well vary across different runtime implementations, but I'll use Android's old Dalvik runtime as an example.
A jobject
, which is defined as a _jobject*
, is an indirect reference. Rather than being used as a normal pointer, the bits of the pointer are used to encode a reference type (local, global, weak global) and a reference table index (source).
So when you pass a jobject
to some JNI function, e.g. NewGlobalRef
, that jobject
will be passed on to dvmDecodeIndirectRef
, which determines the reference type, and returns the corresponding Object*
from the appropriate reference table.
Upvotes: 0
Reputation: 57183
JNI is not a C++ interface, it is a pure C interface. Luckily, JNI has a C++ wrapper, to reduce the boilerplate code when C++ compiler can help, and also avoid (some) mistakes where the C++ type system can reduce ambiguity.
Under the C++ hood that you posted, all JNI objects use black-box handles (you may call them object references) that are interpreted by the JNI functions. On Dalvik JVM, some of these handles were simply pointers into JVM internal tables, but this was an implementation detail that could only be relevant for some debugging.
This implementation detail caused significant troubles when switching to other JVMs, including the modern Android ART, because using pointers, we could sometimes get away with global references mixed with local references, etc.
Upvotes: 0