ART: Add Field methods
Add GetFieldName, GetFieldDeclaringClass, GetFieldModifiers
and IsFieldSynthetic support. Add tests.
Bug: 34113943
Test: m test-art-host-run-test-918-fields
Change-Id: Id33b8c54c250f73f0658ec45ccb2b55eccb37623
diff --git a/test/918-fields/build b/test/918-fields/build
new file mode 100755
index 0000000..898e2e5
--- /dev/null
+++ b/test/918-fields/build
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+./default-build "$@" --experimental agents
diff --git a/test/918-fields/expected.txt b/test/918-fields/expected.txt
new file mode 100644
index 0000000..39d3e70
--- /dev/null
+++ b/test/918-fields/expected.txt
@@ -0,0 +1,16 @@
+[PI, D, null]
+class java.lang.Math
+25
+false
+[value, I, null]
+class java.lang.Integer
+18
+false
+[this$0, LMain;, null]
+class Main$Foo
+4112
+true
+[VAL, I, null]
+interface Main$Bar
+25
+false
diff --git a/test/918-fields/fields.cc b/test/918-fields/fields.cc
new file mode 100644
index 0000000..c7fca06
--- /dev/null
+++ b/test/918-fields/fields.cc
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fields.h"
+
+#include <stdio.h>
+
+#include "base/macros.h"
+#include "jni.h"
+#include "openjdkjvmti/jvmti.h"
+#include "ScopedLocalRef.h"
+
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
+namespace art {
+namespace Test918Fields {
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getFieldName(
+ JNIEnv* env, jclass klass, jobject field) {
+ jfieldID id = env->FromReflectedField(field);
+
+ char* name;
+ char* sig;
+ char* gen;
+ // Note: technically putting the caller class here is wrong, but we don't need it, anyways.
+ jvmtiError result = jvmti_env->GetFieldName(klass, id, &name, &sig, &gen);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running GetFieldName: %s\n", err);
+ return nullptr;
+ }
+
+ auto callback = [&](jint i) {
+ if (i == 0) {
+ return name == nullptr ? nullptr : env->NewStringUTF(name);
+ } else if (i == 1) {
+ return sig == nullptr ? nullptr : env->NewStringUTF(sig);
+ } else {
+ return gen == nullptr ? nullptr : env->NewStringUTF(gen);
+ }
+ };
+ jobjectArray ret = CreateObjectArray(env, 3, "java/lang/String", callback);
+
+ // Need to deallocate the strings.
+ if (name != nullptr) {
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(name));
+ }
+ if (sig != nullptr) {
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig));
+ }
+ if (gen != nullptr) {
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(gen));
+ }
+
+ // Also run GetMethodName with all parameter pointers null to check for segfaults.
+ jvmtiError result2 = jvmti_env->GetFieldName(klass, id, nullptr, nullptr, nullptr);
+ if (result2 != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result2, &err);
+ printf("Failure running GetFieldName(null, null, null): %s\n", err);
+ return nullptr;
+ }
+
+ return ret;
+}
+
+extern "C" JNIEXPORT jclass JNICALL Java_Main_getFieldDeclaringClass(
+ JNIEnv* env, jclass klass, jobject field) {
+ jfieldID id = env->FromReflectedField(field);
+
+ jclass declaring_class;
+ jvmtiError result = jvmti_env->GetFieldDeclaringClass(klass, id, &declaring_class);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running GetFieldDeclaringClass: %s\n", err);
+ return nullptr;
+ }
+
+ return declaring_class;
+}
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_getFieldModifiers(
+ JNIEnv* env, jclass klass, jobject field) {
+ jfieldID id = env->FromReflectedField(field);
+
+ jint modifiers;
+ jvmtiError result = jvmti_env->GetFieldModifiers(klass, id, &modifiers);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running GetFieldModifiers: %s\n", err);
+ return 0;
+ }
+
+ return modifiers;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isFieldSynthetic(
+ JNIEnv* env, jclass klass, jobject field) {
+ jfieldID id = env->FromReflectedField(field);
+
+ jboolean synth;
+ jvmtiError result = jvmti_env->IsFieldSynthetic(klass, id, &synth);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running IsFieldSynthetic: %s\n", err);
+ return 0;
+ }
+
+ return synth;
+}
+
+// Don't do anything
+jint OnLoad(JavaVM* vm,
+ char* options ATTRIBUTE_UNUSED,
+ void* reserved ATTRIBUTE_UNUSED) {
+ if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
+ printf("Unable to get jvmti env!\n");
+ return 1;
+ }
+ SetAllCapabilities(jvmti_env);
+ return 0;
+}
+
+} // namespace Test918Fields
+} // namespace art
diff --git a/test/918-fields/fields.h b/test/918-fields/fields.h
new file mode 100644
index 0000000..89bd161
--- /dev/null
+++ b/test/918-fields/fields.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_TEST_918_FIELDS_FIELDS_H_
+#define ART_TEST_918_FIELDS_FIELDS_H_
+
+#include <jni.h>
+
+namespace art {
+namespace Test918Fields {
+
+jint OnLoad(JavaVM* vm, char* options, void* reserved);
+
+} // namespace Test918Fields
+} // namespace art
+
+#endif // ART_TEST_918_FIELDS_FIELDS_H_
diff --git a/test/918-fields/info.txt b/test/918-fields/info.txt
new file mode 100644
index 0000000..875a5f6
--- /dev/null
+++ b/test/918-fields/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/918-fields/run b/test/918-fields/run
new file mode 100755
index 0000000..4379349
--- /dev/null
+++ b/test/918-fields/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+./default-run "$@" --experimental agents \
+ --experimental runtime-plugins \
+ --jvmti
diff --git a/test/918-fields/src/Main.java b/test/918-fields/src/Main.java
new file mode 100644
index 0000000..8af6e7b
--- /dev/null
+++ b/test/918-fields/src/Main.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[1]);
+
+ doTest();
+ }
+
+ public static void doTest() throws Exception {
+ testField(Math.class, "PI");
+ testField(Integer.class, "value");
+ testField(Foo.class, "this$0");
+ testField(Bar.class, "VAL");
+ }
+
+ private static void testField(Class<?> base, String fieldName)
+ throws Exception {
+ Field f = base.getDeclaredField(fieldName);
+ String[] result = getFieldName(f);
+ System.out.println(Arrays.toString(result));
+
+ Class<?> declClass = getFieldDeclaringClass(f);
+ if (base != declClass) {
+ throw new RuntimeException("Declaring class not equal: " + base + " vs " + declClass);
+ }
+ System.out.println(declClass);
+
+ int modifiers = getFieldModifiers(f);
+ if (modifiers != f.getModifiers()) {
+ throw new RuntimeException("Modifiers not equal: " + f.getModifiers() + " vs " + modifiers);
+ }
+ System.out.println(modifiers);
+
+ boolean synth = isFieldSynthetic(f);
+ if (synth != f.isSynthetic()) {
+ throw new RuntimeException("Synthetic not equal: " + f.isSynthetic() + " vs " + synth);
+ }
+ System.out.println(synth);
+ }
+
+ private static native String[] getFieldName(Field f);
+ private static native Class<?> getFieldDeclaringClass(Field f);
+ private static native int getFieldModifiers(Field f);
+ private static native boolean isFieldSynthetic(Field f);
+
+ private class Foo {
+ }
+
+ private static interface Bar {
+ public static int VAL = 1;
+ }
+}
diff --git a/test/Android.bp b/test/Android.bp
index 5a2c902..26c4f93 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -260,6 +260,7 @@
"911-get-stack-trace/stack_trace.cc",
"912-classes/classes.cc",
"913-heaps/heaps.cc",
+ "918-fields/fields.cc",
],
shared_libs: [
"libbase",
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index ec1f6ba..90dd36e 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -290,6 +290,7 @@
915-obsolete-2 \
916-obsolete-jit \
917-fields-transformation \
+ 918-fields \
ifneq (,$(filter target,$(TARGET_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index 79c17d7..821e254 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -37,6 +37,7 @@
#include "911-get-stack-trace/stack_trace.h"
#include "912-classes/classes.h"
#include "913-heaps/heaps.h"
+#include "918-fields/fields.h"
namespace art {
@@ -70,6 +71,7 @@
{ "915-obsolete-2", common_redefine::OnLoad, nullptr },
{ "916-obsolete-jit", common_redefine::OnLoad, nullptr },
{ "917-fields-transformation", common_redefine::OnLoad, nullptr },
+ { "918-fields", Test918Fields::OnLoad, nullptr },
};
static AgentLib* FindAgent(char* name) {