Allow native methods to declare they don't need a JNIEnv*.
Bug: 3069458
Change-Id: Ic9a6c562c5abf9607dd4c8a71b0d1e389e6d340b
diff --git a/vm/Jni.cpp b/vm/Jni.cpp
index 7abe26e..7da1310 100644
--- a/vm/Jni.cpp
+++ b/vm/Jni.cpp
@@ -716,6 +716,15 @@
return false;
}
+ // If a signature starts with a '!', we take that as a sign that the native code doesn't
+ // need a JNIEnv* passed in.
+ bool needsJniEnv = true;
+ if (*signature == '!') {
+ needsJniEnv = false;
+ ++signature;
+ LOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
+ }
+
Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
if (method == NULL) {
method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
@@ -730,11 +739,26 @@
return false;
}
+ if (!needsJniEnv) {
+ // In this case, we have extra constraints to check...
+ if (dvmIsSynchronizedMethod(method)) {
+ LOGE("fast JNI method %s.%s:%s cannot be synchronized",
+ clazz->descriptor, methodName, signature);
+ return false;
+ }
+ if (!dvmIsStaticMethod(method)) {
+ LOGE("fast JNI method %s.%s:%s cannot be non-static",
+ clazz->descriptor, methodName, signature);
+ return false;
+ }
+ }
+
if (method->nativeFunc != dvmResolveNativeMethod) {
/* this is allowed, but unusual */
LOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
}
+ method->needsJniEnv = needsJniEnv;
dvmUseJNIBridge(method, fnPtr);
LOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
@@ -1059,9 +1083,10 @@
assert(method->insns != NULL);
COMPUTE_STACK_SUM(self);
- dvmPlatformInvoke(env, (ClassObject*)staticMethodClass,
- method->jniArgInfo, method->insSize, modArgs, method->shorty,
- (void*)method->insns, pResult);
+ dvmPlatformInvoke(method->needsJniEnv ? env : NULL,
+ (ClassObject*)staticMethodClass,
+ method->jniArgInfo, method->insSize, modArgs, method->shorty,
+ (void*)method->insns, pResult);
CHECK_STACK_SUM(self);
dvmChangeStatus(self, oldStatus);
@@ -1117,9 +1142,9 @@
ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
COMPUTE_STACK_SUM(self);
- dvmPlatformInvoke(self->jniEnv, NULL,
- method->jniArgInfo, method->insSize, modArgs, method->shorty,
- (void*)method->insns, pResult);
+ dvmPlatformInvoke(method->needsJniEnv ? self->jniEnv : NULL, NULL,
+ method->jniArgInfo, method->insSize, modArgs, method->shorty,
+ (void*)method->insns, pResult);
CHECK_STACK_SUM(self);
dvmChangeStatus(self, oldStatus);
@@ -1146,9 +1171,10 @@
ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
COMPUTE_STACK_SUM(self);
- dvmPlatformInvoke(self->jniEnv, (ClassObject*)staticMethodClass,
- method->jniArgInfo, method->insSize, args, method->shorty,
- (void*)method->insns, pResult);
+ dvmPlatformInvoke(method->needsJniEnv ? self->jniEnv : NULL,
+ (ClassObject*)staticMethodClass,
+ method->jniArgInfo, method->insSize, args, method->shorty,
+ (void*)method->insns, pResult);
CHECK_STACK_SUM(self);
dvmChangeStatus(self, oldStatus);
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index 5858e86..d3c3f0a 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -533,6 +533,9 @@
*/
DalvikBridgeFunc nativeFunc;
+ /* Whether this native method needs a JNIEnv*. */
+ bool needsJniEnv;
+
/*
* Register map data, if available. This will point into the DEX file
* if the data was computed during pre-verification, or into the