graph TB
jstring-->|soa.decode|mirror::String*
mirror::String*-->|encode/AddLocalReference|jstring
mirror::String*-->char*
char*-->|mirror::String::AllocFromModifiedUtf8|mirror::String*
jmethodid-->|decode|ArtMethod*
ArtMethod*-->|encode|jmethodid
jobject("jobject/IndirectRef")-->|decode|mirrorObject("art::mirror::Object*")
mirrorObject-->|Assign/Compress|StackReference("art::StackReference<mirror::Object>*")
StackReference-->|AsMirrorPtr/UnCompress|mirrorObject
StackReference-->|OwnedBy|Handle("art::Handle~T~")
StackHandleScope-->|Provided|Handle
StackHandleScope-->|OwnsMulti|StackReference
ThreadTlsPtr-->|OwnsLinkedList|StackHandleScope
mirrorObject-->|encode|jobject
//8.2.2 ScopedObjectAccess等辅助类
ArtMethod* DecodeMethod(jmethodID mid) const SHARED_REQUIRES(Locks::mutator_lock_) {
Locks::mutator_lock_->AssertSharedHeld(Self());
return reinterpret_cast<ArtMethod*>(mid);//main
}
jmethodID EncodeMethod(ArtMethod* method) const SHARED_REQUIRES(Locks::mutator_lock_) {
Locks::mutator_lock_->AssertSharedHeld(Self());
return reinterpret_cast<jmethodID>(method);//main
}
/*
* Add a local reference for an object to the indirect reference table associated with the
* current stack frame. When the native function returns, the reference will be discarded.
*
* We need to allow the same reference to be added multiple times, and cope with nullptr.
*
* This will be called on otherwise unreferenced objects. We cannot do GC allocations here, and
* it's best if we don't grab a mutex.
*/
template<typename T>
T AddLocalReference(mirror::Object* obj) const SHARED_REQUIRES(Locks::mutator_lock_) {
return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj);
}
template<typename T>
T Decode(jobject obj) const
SHARED_REQUIRES(Locks::mutator_lock_) {
Locks::mutator_lock_->AssertSharedHeld(Self());
return down_cast<T>(Self()->DecodeJObject(obj));//main
}
// JNI local references.
IndirectReferenceTable locals GUARDED_BY(Locks::mutator_lock_);
template<typename T>
inline T JNIEnvExt::AddLocalReference(mirror::Object* obj) {
IndirectRef ref = locals.Add(local_ref_cookie, obj);
return reinterpret_cast<T>(ref);
}
libnativehelper/include_jni/jni.h
/* Primitive types that match up with Java equivalents. */
typedef uint8_t jboolean; /* unsigned 8 bits */
typedef int8_t jbyte; /* signed 8 bits */
typedef uint16_t jchar; /* unsigned 16 bits */
typedef int16_t jshort; /* signed 16 bits */
typedef int32_t jint; /* signed 32 bits */
typedef int64_t jlong; /* signed 64 bits */
typedef float jfloat; /* 32-bit IEEE 754 */
typedef double jdouble; /* 64-bit IEEE 754 */
/* "cardinal indices and sizes" */
typedef jint jsize;
class _jobject {};
class _jclass : public _jobject {};
class _jstring : public _jobject {};
class _jarray : public _jobject {};
class _jobjectArray : public _jarray {};
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};
class _jthrowable : public _jobject {};
typedef _jobject* jobject;
typedef _jclass* jclass;
typedef _jstring* jstring;
typedef _jarray* jarray;
typedef _jobjectArray* jobjectArray;
typedef _jbooleanArray* jbooleanArray;
typedef _jbyteArray* jbyteArray;
typedef _jcharArray* jcharArray;
typedef _jshortArray* jshortArray;
typedef _jintArray* jintArray;
typedef _jlongArray* jlongArray;
typedef _jfloatArray* jfloatArray;
typedef _jdoubleArray* jdoubleArray;
typedef _jthrowable* jthrowable;
typedef _jobject* jweak;
struct _jfieldID; /* opaque structure */
typedef struct _jfieldID* jfieldID; /* field IDs */
struct _jmethodID; /* opaque structure */
typedef struct _jmethodID* jmethodID; /* method IDs */
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
jobject NewObject(jclass clazz, jmethodID methodID, ...)
{
va_list args;
va_start(args, methodID);
jobject result = functions->NewObjectV(this, clazz, methodID, args);
va_end(args);
return result;
}
libnativehelper/platform_include/nativehelper/jni_macros.h
#define NATIVE_METHOD(className, functionName, signature) \
MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) //java方法对应的native实现函数方法名规范
art/runtime/jni_internal.cc
static const char* GetStringUTFChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
if (is_copy != nullptr) {
*is_copy = JNI_TRUE;
}
ScopedObjectAccess soa(env);
ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
size_t byte_count = s->GetUtfLength();
char* bytes = new char[byte_count + 1];
CHECK(bytes != nullptr); // bionic aborts anyway.
if (s->IsCompressed()) {
for (size_t i = 0; i < byte_count; ++i) {
bytes[i] = s->CharAt(i);
}
} else {
const uint16_t* chars = s->GetValue();
ConvertUtf16ToModifiedUtf8(bytes, byte_count, chars, s->GetLength());
}
bytes[byte_count] = '\0';
return bytes;
}
static void ReleaseStringUTFChars(JNIEnv*, jstring, const char* chars) {
delete[] chars;
}
static jstring NewStringUTF(JNIEnv* env, const char* utf) {
if (utf == nullptr) {
return nullptr;
}
ScopedObjectAccess soa(env);
mirror::String* result = mirror::String::AllocFromModifiedUtf8(soa.Self(), utf);
return soa.AddLocalReference<jstring>(result);
}
static jobject NewObjectV(JNIEnv* env, jclass java_class, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(java_class);
CHECK_NON_NULL_ARGUMENT(mid);
ScopedObjectAccess soa(env);
mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
if (c == nullptr) {
return nullptr;
}
if (c->IsStringClass()) {
// Replace calls to String.<init> with equivalent StringFactory call.
jmethodID sf_mid = WellKnownClasses::StringInitToStringFactoryMethodID(mid);
return CallStaticObjectMethodV(env, WellKnownClasses::java_lang_StringFactory, sf_mid, args);
}
mirror::Object* result = c->AllocObject(soa.Self());
if (result == nullptr) {
return nullptr;
}
jobject local_result = soa.AddLocalReference<jobject>(result);
CallNonvirtualVoidMethodV(env, local_result, java_class, mid, args);
if (soa.Self()->IsExceptionPending()) {
return nullptr;
}
return local_result;
art/runtime/thread.cc
HandleScope* GetTopHandleScope() {
return tlsPtr_.top_handle_scope;
}
void PushHandleScope(HandleScope* handle_scope) {
DCHECK_EQ(handle_scope->GetLink(), tlsPtr_.top_handle_scope);
tlsPtr_.top_handle_scope = handle_scope;
}
ObjPtr<mirror::Object> Thread::DecodeJObject(jobject obj) const {
if (obj == nullptr) {
return nullptr;
}
//将jobject转换为IndirectRef
IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
IndirectRefKind kind = IndirectReferenceTable::GetIndirectRefKind(ref);
ObjPtr<mirror::Object> result;
bool expect_null = false;
// The "kinds" below are sorted by the frequency we expect to encounter them.
if (kind == kLocal) {//如果是local型引用,则从local的IRTable中找到对应的对象
IndirectReferenceTable& locals = tlsPtr_.jni_env->locals_;
// Local references do not need a read barrier.
result = locals.Get<kWithoutReadBarrier>(ref);
} else if (kind == kHandleScopeOrInvalid) {
// TODO: make stack indirect reference table lookup more efficient.
// Check if this is a local reference in the handle scope.
if (LIKELY(HandleScopeContains(obj))) {
//如果是栈上传递过来的对象(如方法参数),则可以直接转换成mirror Object对象
// Read from handle scope.
result = reinterpret_cast<StackReference<mirror::Object>*>(obj)->AsMirrorPtr();
VerifyObject(result);
} else {
tlsPtr_.jni_env->vm_->JniAbortF(nullptr, "use of invalid jobject %p", obj);
expect_null = true;
result = nullptr;
}
} else if (kind == kGlobal) {
//对Global型对象的处理,想必是要交给JavaVMExt globals_来处理
result = tlsPtr_.jni_env->vm_->DecodeGlobal(ref);
} else {//对WeakGlobal型对象的处理,如果该对象已经回收,则返回nullptr
DCHECK_EQ(kind, kWeakGlobal);
result = tlsPtr_.jni_env->vm_->DecodeWeakGlobal(const_cast<Thread*>(this), ref);
if (Runtime::Current()->IsClearedJniWeakGlobal(result)) {
//对象被回收了,所以返回nullptr
// This is a special case where it's okay to return null.
expect_null = true;
result = nullptr;
}
}
if (UNLIKELY(!expect_null && result == nullptr)) {
tlsPtr_.jni_env->vm_->JniAbortF(nullptr, "use of deleted %s %p",
ToStr<IndirectRefKind>(kind).c_str(), obj);
}
return result;
}
IrtEntry* const table_;
size_t i_;
const size_t capacity_;
template<ReadBarrierOption kReadBarrierOption>
inline mirror::Object* IndirectReferenceTable::Get(IndirectRef iref) const {
if (!GetChecked(iref)) {
return nullptr;
}
uint32_t idx = ExtractIndex(iref);
mirror::Object* obj = table_[idx].GetReference()->Read<kReadBarrierOption>();
VerifyObject(obj);
return obj;
}
IndirectRef IndirectReferenceTable::Add(uint32_t cookie, mirror::Object* obj) {
// We know there's enough room in the table. Now we just need to find
// the right spot. If there's a hole, find it and fill it; otherwise,
// add to the end of the list.
IndirectRef result;
......
table_[index].Add(obj);
result = ToIndirectRef(index);
return result;
/*
* The object pointer itself is subject to relocation in some GC
* implementations, so we shouldn't really be using it here.
*/
IndirectRef ToIndirectRef(uint32_t tableIndex) const {
DCHECK_LT(tableIndex, 65536U);
uint32_t serialChunk = table_[tableIndex].GetSerial();
uintptr_t uref = (serialChunk << 20) | (tableIndex << 2) | kind_;
return reinterpret_cast<IndirectRef>(uref);
}
class IrtEntry {
void Add(mirror::Object* obj) SHARED_REQUIRES(Locks::mutator_lock_) {
++serial_;
if (serial_ == kIRTPrevCount) {
serial_ = 0;
}
references_[serial_] = GcRoot<mirror::Object>(obj);
}
GcRoot<mirror::Object>* GetReference() {
DCHECK_LT(serial_, kIRTPrevCount);
return &references_[serial_];
}
void SetReference(mirror::Object* obj) {
DCHECK_LT(serial_, kIRTPrevCount);
references_[serial_] = GcRoot<mirror::Object>(obj);
}
private:
uint32_t serial_;
GcRoot<mirror::Object> references_[kIRTPrevCount];
}
template<class MirrorType>
class GcRoot {
public:
template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
ALWAYS_INLINE MirrorType* Read(GcRootSource* gc_root_source = nullptr) const
SHARED_REQUIRES(Locks::mutator_lock_);
art/rumtime/mirror/String.h
uint16_t value_[0];
uint16_t* GetValue() SHARED_REQUIRES(Locks::mutator_lock_) {
return &value_[0];
}
art/runtime/native/java_lang_reflect_Method.cc
static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver,
jobjectArray javaArgs) {
ScopedFastNativeObjectAccess soa(env);
return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
}