Remove some SOA from JNI internal.
Remove or reduce scope of scoped object accesses in JNI internal. Turn a
PrettyMethod and string compare into a pointer comparison.
Change-Id: I6f8ac8f6a4741916769288c4d6d411c7e0f40ef4
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 8a16bc7..d2c8fc4 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -232,11 +232,12 @@
return soa.EncodeMethod(method);
}
-static ClassLoader* GetClassLoader(Thread* self)
+static ClassLoader* GetClassLoader(const ScopedObjectAccess& soa)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- AbstractMethod* method = self->GetCurrentMethod();
- if (method == NULL || PrettyMethod(method, false) == "java.lang.Runtime.nativeLoad") {
- return self->GetClassLoaderOverride();
+ AbstractMethod* method = soa.Self()->GetCurrentMethod();
+ if (method == NULL ||
+ method == soa.DecodeMethod(WellKnownClasses::java_lang_Runtime_nativeLoad)) {
+ return soa.Self()->GetClassLoaderOverride();
}
return method->GetDeclaringClass()->GetClassLoader();
}
@@ -253,7 +254,7 @@
Class* field_type;
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
if (sig[1] != '\0') {
- ClassLoader* cl = GetClassLoader(soa.Self());
+ ClassLoader* cl = GetClassLoader(soa);
field_type = class_linker->FindClass(sig, cl);
} else {
field_type = class_linker->FindPrimitiveClass(*sig);
@@ -313,8 +314,6 @@
int ThrowNewException(JNIEnv* env, jclass exception_class, const char* msg, jobject cause)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
- ScopedObjectAccess soa(env);
-
// Turn the const char* into a java.lang.String.
ScopedLocalRef<jstring> s(env, env->NewStringUTF(msg));
if (msg != NULL && s.get() == NULL) {
@@ -339,6 +338,7 @@
}
jmethodID mid = env->GetMethodID(exception_class, "<init>", signature);
if (mid == NULL) {
+ ScopedObjectAccess soa(env);
LOG(ERROR) << "No <init>" << signature << " in "
<< PrettyClass(soa.Decode<Class*>(exception_class));
return JNI_ERR;
@@ -349,6 +349,7 @@
return JNI_ERR;
}
+ ScopedObjectAccess soa(env);
soa.Self()->SetException(soa.Decode<Throwable*>(exception.get()));
return JNI_OK;
@@ -590,7 +591,7 @@
std::string descriptor(NormalizeJniClassDescriptor(name));
Class* c = NULL;
if (runtime->IsStarted()) {
- ClassLoader* cl = GetClassLoader(soa.Self());
+ ClassLoader* cl = GetClassLoader(soa);
c = class_linker->FindClass(descriptor.c_str(), cl);
} else {
c = class_linker->FindSystemClass(descriptor.c_str());
@@ -712,11 +713,10 @@
}
static jint PushLocalFrame(JNIEnv* env, jint capacity) {
- ScopedObjectAccess soa(env);
- if (EnsureLocalCapacity(soa, capacity, "PushLocalFrame") != JNI_OK) {
+ if (EnsureLocalCapacity(env, capacity, "PushLocalFrame") != JNI_OK) {
return JNI_ERR;
}
- soa.Env()->PushFrame(capacity);
+ static_cast<JNIEnvExt*>(env)->PushFrame(capacity);
return JNI_OK;
}
@@ -728,8 +728,7 @@
}
static jint EnsureLocalCapacity(JNIEnv* env, jint desired_capacity) {
- ScopedObjectAccess soa(env);
- return EnsureLocalCapacity(soa, desired_capacity, "EnsureLocalCapacity");
+ return EnsureLocalCapacity(env, desired_capacity, "EnsureLocalCapacity");
}
static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
@@ -749,10 +748,10 @@
if (obj == NULL) {
return;
}
- ScopedObjectAccess soa(env);
- JavaVMExt* vm = soa.Vm();
+ JavaVMExt* vm = reinterpret_cast<JNIEnvExt*>(env)->vm;
IndirectReferenceTable& globals = vm->globals;
- MutexLock mu(soa.Self(), vm->globals_lock);
+ Thread* self = reinterpret_cast<JNIEnvExt*>(env)->self;
+ MutexLock mu(self, vm->globals_lock);
if (!globals.Remove(IRT_FIRST_SEGMENT, obj)) {
LOG(WARNING) << "JNI WARNING: DeleteGlobalRef(" << obj << ") "
@@ -796,10 +795,9 @@
if (obj == NULL) {
return;
}
- ScopedObjectAccess soa(env);
- IndirectReferenceTable& locals = soa.Env()->locals;
+ IndirectReferenceTable& locals = reinterpret_cast<JNIEnvExt*>(env)->locals;
- uint32_t cookie = soa.Env()->local_ref_cookie;
+ uint32_t cookie = reinterpret_cast<JNIEnvExt*>(env)->local_ref_cookie;
if (!locals.Remove(cookie, obj)) {
// Attempting to delete a local reference that is not in the
// topmost local reference frame is a no-op. DeleteLocalRef returns
@@ -1730,7 +1728,6 @@
}
static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* is_copy) {
- ScopedObjectAccess soa(env);
return GetStringChars(env, java_string, is_copy);
}
@@ -1740,13 +1737,13 @@
}
static const char* GetStringUTFChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
- ScopedObjectAccess soa(env);
if (java_string == NULL) {
return NULL;
}
if (is_copy != NULL) {
*is_copy = JNI_TRUE;
}
+ ScopedObjectAccess soa(env);
String* s = soa.Decode<String*>(java_string);
size_t byte_count = s->GetUtfLength();
char* bytes = new char[byte_count + 1];
@@ -1758,7 +1755,6 @@
}
static void ReleaseStringUTFChars(JNIEnv* env, jstring, const char* chars) {
- ScopedObjectAccess soa(env);
delete[] chars;
}
@@ -1863,8 +1859,7 @@
}
static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void*, jint mode) {
- ScopedObjectAccess soa(env);
- ReleasePrimitiveArray(soa, array, mode);
+ ReleasePrimitiveArray(env, array, mode);
}
static jboolean* GetBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* is_copy) {
@@ -1908,43 +1903,35 @@
}
static void ReleaseBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean*, jint mode) {
- ScopedObjectAccess soa(env);
- ReleasePrimitiveArray(soa, array, mode);
+ ReleasePrimitiveArray(env, array, mode);
}
static void ReleaseByteArrayElements(JNIEnv* env, jbyteArray array, jbyte*, jint mode) {
- ScopedObjectAccess soa(env);
- ReleasePrimitiveArray(soa, array, mode);
+ ReleasePrimitiveArray(env, array, mode);
}
static void ReleaseCharArrayElements(JNIEnv* env, jcharArray array, jchar*, jint mode) {
- ScopedObjectAccess soa(env);
- ReleasePrimitiveArray(soa, array, mode);
+ ReleasePrimitiveArray(env, array, mode);
}
static void ReleaseDoubleArrayElements(JNIEnv* env, jdoubleArray array, jdouble*, jint mode) {
- ScopedObjectAccess soa(env);
- ReleasePrimitiveArray(soa, array, mode);
+ ReleasePrimitiveArray(env, array, mode);
}
static void ReleaseFloatArrayElements(JNIEnv* env, jfloatArray array, jfloat*, jint mode) {
- ScopedObjectAccess soa(env);
- ReleasePrimitiveArray(soa, array, mode);
+ ReleasePrimitiveArray(env, array, mode);
}
static void ReleaseIntArrayElements(JNIEnv* env, jintArray array, jint*, jint mode) {
- ScopedObjectAccess soa(env);
- ReleasePrimitiveArray(soa, array, mode);
+ ReleasePrimitiveArray(env, array, mode);
}
static void ReleaseLongArrayElements(JNIEnv* env, jlongArray array, jlong*, jint mode) {
- ScopedObjectAccess soa(env);
- ReleasePrimitiveArray(soa, array, mode);
+ ReleasePrimitiveArray(env, array, mode);
}
static void ReleaseShortArrayElements(JNIEnv* env, jshortArray array, jshort*, jint mode) {
- ScopedObjectAccess soa(env);
- ReleasePrimitiveArray(soa, array, mode);
+ ReleasePrimitiveArray(env, array, mode);
}
static void GetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize length, jboolean* buf) {
@@ -2108,7 +2095,6 @@
}
static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
- ScopedObjectAccess soa(env);
Runtime* runtime = Runtime::Current();
if (runtime != NULL) {
*vm = runtime->GetJavaVM();
@@ -2119,8 +2105,6 @@
}
static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
- ScopedObjectAccess soa(env);
-
// The address may not be NULL, and the capacity must be > 0.
CHECK(address != NULL); // TODO: ReportJniError
CHECK_GT(capacity, 0); // TODO: ReportJniError
@@ -2134,22 +2118,18 @@
jobject result = env->NewObject(WellKnownClasses::java_nio_ReadWriteDirectByteBuffer,
WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_init,
address_arg, capacity_arg);
- return soa.Self()->IsExceptionPending() ? NULL : result;
+ return static_cast<JNIEnvExt*>(env)->self->IsExceptionPending() ? NULL : result;
}
static void* GetDirectBufferAddress(JNIEnv* env, jobject java_buffer) {
- ScopedObjectAccess soa(env);
return reinterpret_cast<void*>(env->GetIntField(java_buffer, WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_effectiveDirectAddress));
}
static jlong GetDirectBufferCapacity(JNIEnv* env, jobject java_buffer) {
- ScopedObjectAccess soa(env);
return static_cast<jlong>(env->GetIntField(java_buffer, WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_capacity));
}
static jobjectRefType GetObjectRefType(JNIEnv* env, jobject java_object) {
- ScopedObjectAccess soa(env);
-
CHECK(java_object != NULL); // TODO: ReportJniError
// Do we definitely know what kind of reference this is?
@@ -2157,7 +2137,7 @@
IndirectRefKind kind = GetIndirectRefKind(ref);
switch (kind) {
case kLocal:
- if (soa.Env()->locals.Get(ref) != kInvalidIndirectRefObject) {
+ if (static_cast<JNIEnvExt*>(env)->locals.Get(ref) != kInvalidIndirectRefObject) {
return JNILocalRefType;
}
return JNIInvalidRefType;
@@ -2167,22 +2147,24 @@
return JNIWeakGlobalRefType;
case kSirtOrInvalid:
// Is it in a stack IRT?
- if (soa.Self()->SirtContains(java_object)) {
+ if (static_cast<JNIEnvExt*>(env)->self->SirtContains(java_object)) {
return JNILocalRefType;
}
- if (!soa.Vm()->work_around_app_jni_bugs) {
+ if (!static_cast<JNIEnvExt*>(env)->vm->work_around_app_jni_bugs) {
return JNIInvalidRefType;
}
// If we're handing out direct pointers, check whether it's a direct pointer
// to a local reference.
- if (soa.Decode<Object*>(java_object) == reinterpret_cast<Object*>(java_object)) {
- if (soa.Env()->locals.ContainsDirectPointer(reinterpret_cast<Object*>(java_object))) {
- return JNILocalRefType;
+ {
+ ScopedObjectAccess soa(env);
+ if (soa.Decode<Object*>(java_object) == reinterpret_cast<Object*>(java_object)) {
+ if (soa.Env()->locals.ContainsDirectPointer(reinterpret_cast<Object*>(java_object))) {
+ return JNILocalRefType;
+ }
}
}
-
return JNIInvalidRefType;
}
LOG(FATAL) << "IndirectRefKind[" << kind << "]";
@@ -2190,18 +2172,18 @@
}
private:
- static jint EnsureLocalCapacity(const ScopedObjectAccess& soa, jint desired_capacity,
- const char* caller)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ static jint EnsureLocalCapacity(JNIEnv* env, jint desired_capacity,
+ const char* caller) {
// TODO: we should try to expand the table if necessary.
if (desired_capacity < 1 || desired_capacity > static_cast<jint>(kLocalsMax)) {
LOG(ERROR) << "Invalid capacity given to " << caller << ": " << desired_capacity;
return JNI_ERR;
}
// TODO: this isn't quite right, since "capacity" includes holes.
- size_t capacity = soa.Env()->locals.Capacity();
+ size_t capacity = static_cast<JNIEnvExt*>(env)->locals.Capacity();
bool okay = (static_cast<jint>(kLocalsMax - capacity) >= desired_capacity);
if (!okay) {
+ ScopedObjectAccess soa(env);
soa.Self()->ThrowOutOfMemoryError(caller);
}
return okay ? JNI_OK : JNI_ERR;
@@ -2228,10 +2210,9 @@
}
template <typename ArrayT>
- static void ReleasePrimitiveArray(ScopedObjectAccess& soa, ArrayT java_array,
- jint mode)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ static void ReleasePrimitiveArray(JNIEnv* env, ArrayT java_array, jint mode) {
if (mode != JNI_COMMIT) {
+ ScopedObjectAccess soa(env);
Array* array = soa.Decode<Array*>(java_array);
UnpinPrimitiveArray(soa, array);
}
diff --git a/src/runtime.cc b/src/runtime.cc
index 8d88270..4ecc73a 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -854,6 +854,10 @@
}
self->TransitionFromRunnableToSuspended(kNative);
}
+
+ // Initialize well known classes that may invoke runtime native methods.
+ WellKnownClasses::LateInit(env);
+
VLOG(startup) << "Runtime::InitNativeMethods exiting";
}
diff --git a/src/well_known_classes.cc b/src/well_known_classes.cc
index cb7b70c..80edb52 100644
--- a/src/well_known_classes.cc
+++ b/src/well_known_classes.cc
@@ -60,6 +60,7 @@
jmethodID WellKnownClasses::java_lang_ref_FinalizerReference_add;
jmethodID WellKnownClasses::java_lang_ref_ReferenceQueue_add;
jmethodID WellKnownClasses::java_lang_reflect_InvocationHandler_invoke;
+jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad;
jmethodID WellKnownClasses::java_lang_Short_valueOf;
jmethodID WellKnownClasses::java_lang_Thread_init;
jmethodID WellKnownClasses::java_lang_Thread_run;
@@ -194,6 +195,11 @@
java_lang_Short_valueOf = CachePrimitiveBoxingMethod(env, 'S', "java/lang/Short");
}
+void WellKnownClasses::LateInit(JNIEnv* env) {
+ ScopedLocalRef<jclass> java_lang_Runtime(env, env->FindClass("java/lang/Runtime"));
+ java_lang_Runtime_nativeLoad = CacheMethod(env, java_lang_Runtime.get(), true, "nativeLoad", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;");
+}
+
Class* WellKnownClasses::ToClass(jclass global_jclass) {
return reinterpret_cast<Class*>(Thread::Current()->DecodeJObject(global_jclass));
}
diff --git a/src/well_known_classes.h b/src/well_known_classes.h
index 90b33c1..fd8f19b 100644
--- a/src/well_known_classes.h
+++ b/src/well_known_classes.h
@@ -30,7 +30,8 @@
struct WellKnownClasses {
static void InitClasses(JNIEnv* env);
- static void Init(JNIEnv* env);
+ static void Init(JNIEnv* env); // Run before native methods are registered.
+ static void LateInit(JNIEnv* env); // Run after native methods are registered.
static Class* ToClass(jclass global_jclass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -71,6 +72,7 @@
static jmethodID java_lang_ref_FinalizerReference_add;
static jmethodID java_lang_ref_ReferenceQueue_add;
static jmethodID java_lang_reflect_InvocationHandler_invoke;
+ static jmethodID java_lang_Runtime_nativeLoad;
static jmethodID java_lang_Short_valueOf;
static jmethodID java_lang_Thread_init;
static jmethodID java_lang_Thread_run;