benchmark: Add a build target that's not Android-dependent
Allow building the micronative portion of libartbenchmark as pure JNI without any android
library dependencies.
Bug: 31401609
Change-Id: I99f1466fb668a9ae5dd2f7229dca44d3bb064e15
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
index 94ad015..050100f 100644
--- a/benchmark/Android.bp
+++ b/benchmark/Android.bp
@@ -43,3 +43,31 @@
"-Wno-frame-larger-than=",
],
}
+
+art_cc_library {
+ name: "libartbenchmark-micronative-host",
+ host_supported: true,
+ device_supported: false,
+ defaults: ["art_defaults", "art_debug_defaults"],
+ srcs: [
+ "jni_loader.cc",
+ "micro-native/micro_native.cc",
+ ],
+ shared_libs: [
+ ],
+ static_libs: [
+ ],
+ include_dirs: [
+ "libnativehelper/include/nativehelper" // only for jni.h
+ ],
+ stl: "libc++_static",
+ clang: true,
+ target: {
+ host: {
+ host_ldlibs: ["-ldl", "-lpthread"],
+ },
+ },
+ cflags: [
+ "-Wno-frame-larger-than=",
+ ],
+}
diff --git a/benchmark/micro-native/micro_native.cc b/benchmark/micro-native/micro_native.cc
index 43c29e2..d366d9d 100644
--- a/benchmark/micro-native/micro_native.cc
+++ b/benchmark/micro-native/micro_native.cc
@@ -14,12 +14,26 @@
* limitations under the License.
*/
-#define LOG_TAG "NativeMethods"
+#include <stdio.h>
+#include <jni.h>
+
+#ifndef NATIVE_METHOD
+#define NATIVE_METHOD(className, functionName, signature) \
+ { #functionName, signature, reinterpret_cast<void*>(className ## _ ## functionName) }
+#endif
+#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
+
+#define GLUE4(a, b, c, d) a ## b ## c ## d
+#define GLUE4_(a, b, c, d) GLUE4(a, b, c, d)
#define CLASS_NAME "benchmarks/MicroNative/java/NativeMethods"
+#define CLASS_INFIX benchmarks_MicroNative_java_NativeMethods
-#include "JNIHelp.h"
-#include "JniConstants.h"
+#define NAME_NORMAL_JNI_METHOD(name) GLUE4_(Java_, CLASS_INFIX, _, name)
+#define NAME_CRITICAL_JNI_METHOD(name) GLUE4_(JavaCritical_, CLASS_INFIX, _, name)
+
+#define DEFINE_NORMAL_JNI_METHOD(ret, name) extern "C" JNIEXPORT ret JNICALL GLUE4_(Java_, CLASS_INFIX, _, name)
+#define DEFINE_CRITICAL_JNI_METHOD(ret, name) extern "C" JNIEXPORT ret JNICALL GLUE4_(JavaCritical_, CLASS_INFIX, _, name)
static void NativeMethods_emptyJniStaticSynchronizedMethod0(JNIEnv*, jclass) { }
static void NativeMethods_emptyJniSynchronizedMethod0(JNIEnv*, jclass) { }
@@ -67,17 +81,66 @@
NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6_Fast, "(IIIIII)V"),
};
-static void NativeMethods_emptyJniStaticMethod0_Critical() { }
-static void NativeMethods_emptyJniStaticMethod6_Critical(int, int, int, int, int, int) { }
+// Have both a Java_ and a JavaCritical_ version of the same empty method.
+// The runtime automatically selects the right one when doing a dlsym-based native lookup.
+DEFINE_NORMAL_JNI_METHOD(void, emptyJniStaticMethod0_1Critical)(JNIEnv*, jclass) { }
+DEFINE_CRITICAL_JNI_METHOD(void, emptyJniStaticMethod0_1Critical)() { }
+DEFINE_NORMAL_JNI_METHOD(void, emptyJniStaticMethod6_1Critical)(JNIEnv*, jclass, int, int, int, int, int, int) { }
+DEFINE_CRITICAL_JNI_METHOD(void, emptyJniStaticMethod6_1Critical)(int, int, int, int, int, int) { }
static JNINativeMethod gMethods_Critical[] = {
- NATIVE_METHOD(NativeMethods, emptyJniStaticMethod0_Critical, "()V"),
- NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6_Critical, "(IIIIII)V"),
+ // Don't use NATIVE_METHOD because the name is mangled differently.
+ { "emptyJniStaticMethod0_Critical", "()V",
+ reinterpret_cast<void*>(NAME_CRITICAL_JNI_METHOD(emptyJniStaticMethod0_1Critical)) },
+ { "emptyJniStaticMethod6_Critical", "(IIIIII)V",
+ reinterpret_cast<void*>(NAME_CRITICAL_JNI_METHOD(emptyJniStaticMethod6_1Critical)) }
};
+void jniRegisterNativeMethods(JNIEnv* env,
+ const char* className,
+ const JNINativeMethod* methods,
+ int numMethods) {
+ jclass c = env->FindClass(className);
+ if (c == nullptr) {
+ char* tmp;
+ const char* msg;
+ if (asprintf(&tmp,
+ "Native registration unable to find class '%s'; aborting...",
+ className) == -1) {
+ // Allocation failed, print default warning.
+ msg = "Native registration unable to find class; aborting...";
+ } else {
+ msg = tmp;
+ }
+ env->FatalError(msg);
+ }
+
+ if (env->RegisterNatives(c, methods, numMethods) < 0) {
+ char* tmp;
+ const char* msg;
+ if (asprintf(&tmp, "RegisterNatives failed for '%s'; aborting...", className) == -1) {
+ // Allocation failed, print default warning.
+ msg = "RegisterNatives failed; aborting...";
+ } else {
+ msg = tmp;
+ }
+ env->FatalError(msg);
+ }
+}
+
void register_micro_native_methods(JNIEnv* env) {
jniRegisterNativeMethods(env, CLASS_NAME, gMethods_NormalOnly, NELEM(gMethods_NormalOnly));
jniRegisterNativeMethods(env, CLASS_NAME, gMethods, NELEM(gMethods));
jniRegisterNativeMethods(env, CLASS_NAME, gMethods_Fast, NELEM(gMethods_Fast));
- jniRegisterNativeMethods(env, CLASS_NAME, gMethods_Critical, NELEM(gMethods_Critical));
+
+ if (env->FindClass("dalvik/annotation/optimization/CriticalNative") != nullptr) {
+ // Only register them explicitly if the annotation is present.
+ jniRegisterNativeMethods(env, CLASS_NAME, gMethods_Critical, NELEM(gMethods_Critical));
+ } else {
+ if (env->ExceptionCheck()) {
+ // It will throw NoClassDefFoundError
+ env->ExceptionClear();
+ }
+ }
+ // else let them be registered implicitly.
}