Add test for local-refs being updated by structural-redef
We don't have a good test that local-JNI-refs are correctly updated by
structural redefinition. This adds such a test.
Test: ./test.py --host
Change-Id: I56697fe1a4f9d726b5666c7be2d4036ee248bc58
diff --git a/test/2009-structural-local-ref/expected.txt b/test/2009-structural-local-ref/expected.txt
new file mode 100644
index 0000000..3ad1fbd
--- /dev/null
+++ b/test/2009-structural-local-ref/expected.txt
@@ -0,0 +1,8 @@
+Doing redefinition for instance field
+Result was VirtualString
+Doing redefinition for static field
+Result was StaticString
+Doing redefinition for instance method
+Result was meth
+Doing redefinition for static method
+Result was static-meth
diff --git a/test/2009-structural-local-ref/info.txt b/test/2009-structural-local-ref/info.txt
new file mode 100644
index 0000000..4c9f871
--- /dev/null
+++ b/test/2009-structural-local-ref/info.txt
@@ -0,0 +1,3 @@
+Tests structural redefinition with local-refs
+
+Tests that using the structural redefinition updates JNI local-refs.
diff --git a/test/2009-structural-local-ref/local-ref.cc b/test/2009-structural-local-ref/local-ref.cc
new file mode 100644
index 0000000..9f6ef0b
--- /dev/null
+++ b/test/2009-structural-local-ref/local-ref.cc
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 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 <stdio.h>
+
+#include <vector>
+
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "jni.h"
+#include "jvmti.h"
+
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "scoped_local_ref.h"
+#include "test_env.h"
+
+namespace art {
+namespace Test2009StructuralLocalRef {
+
+extern "C" JNIEXPORT jstring JNICALL Java_art_Test2009_NativeLocalCallStatic(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj, jobject thnk) {
+ jclass obj_klass = env->GetObjectClass(obj);
+ jmethodID run_meth = env->GetMethodID(env->FindClass("java/lang/Runnable"), "run", "()V");
+ env->CallVoidMethod(thnk, run_meth);
+ jmethodID new_method =
+ env->GetStaticMethodID(obj_klass, "getGreetingStatic", "()Ljava/lang/String;");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ } else {
+ return reinterpret_cast<jstring>(env->CallStaticObjectMethod(obj_klass, new_method));
+ }
+}
+
+extern "C" JNIEXPORT jstring JNICALL Java_art_Test2009_NativeLocalCallVirtual(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj, jobject thnk) {
+ jclass obj_klass = env->GetObjectClass(obj);
+ jmethodID run_meth = env->GetMethodID(env->FindClass("java/lang/Runnable"), "run", "()V");
+ env->CallVoidMethod(thnk, run_meth);
+ jmethodID new_method = env->GetMethodID(obj_klass, "getGreeting", "()Ljava/lang/String;");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ } else {
+ return reinterpret_cast<jstring>(env->CallObjectMethod(obj, new_method));
+ }
+}
+extern "C" JNIEXPORT jstring JNICALL Java_art_Test2009_NativeLocalGetIField(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj, jobject thnk) {
+ jclass obj_klass = env->GetObjectClass(obj);
+ jmethodID run_meth = env->GetMethodID(env->FindClass("java/lang/Runnable"), "run", "()V");
+ env->CallVoidMethod(thnk, run_meth);
+ jfieldID new_field = env->GetFieldID(obj_klass, "greeting", "Ljava/lang/String;");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ } else {
+ env->SetObjectField(obj, new_field, env->NewStringUTF("VirtualString"));
+ return reinterpret_cast<jstring>(env->GetObjectField(obj, new_field));
+ }
+}
+extern "C" JNIEXPORT jstring JNICALL Java_art_Test2009_NativeLocalGetSField(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj, jobject thnk) {
+ jclass obj_klass = env->GetObjectClass(obj);
+ jmethodID run_meth = env->GetMethodID(env->FindClass("java/lang/Runnable"), "run", "()V");
+ env->CallVoidMethod(thnk, run_meth);
+ jfieldID new_field = env->GetStaticFieldID(obj_klass, "static_greeting", "Ljava/lang/String;");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ } else {
+ env->SetStaticObjectField(obj_klass, new_field, env->NewStringUTF("StaticString"));
+ return reinterpret_cast<jstring>(env->GetStaticObjectField(obj_klass, new_field));
+ }
+}
+
+} // namespace Test2009StructuralLocalRef
+} // namespace art
diff --git a/test/2009-structural-local-ref/run b/test/2009-structural-local-ref/run
new file mode 100755
index 0000000..03e41a5
--- /dev/null
+++ b/test/2009-structural-local-ref/run
@@ -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-run "$@" --jvmti --runtime-option -Xopaque-jni-ids:true
diff --git a/test/2009-structural-local-ref/src-art/Main.java b/test/2009-structural-local-ref/src-art/Main.java
new file mode 100644
index 0000000..6635228
--- /dev/null
+++ b/test/2009-structural-local-ref/src-art/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ art.Test2009.run();
+ }
+}
diff --git a/test/2009-structural-local-ref/src-art/art/Redefinition.java b/test/2009-structural-local-ref/src-art/art/Redefinition.java
new file mode 120000
index 0000000..81eaf31
--- /dev/null
+++ b/test/2009-structural-local-ref/src-art/art/Redefinition.java
@@ -0,0 +1 @@
+../../../jvmti-common/Redefinition.java
\ No newline at end of file
diff --git a/test/2009-structural-local-ref/src-art/art/Test2009.java b/test/2009-structural-local-ref/src-art/art/Test2009.java
new file mode 100644
index 0000000..7ef9a8b
--- /dev/null
+++ b/test/2009-structural-local-ref/src-art/art/Test2009.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package art;
+
+import dalvik.system.InMemoryDexClassLoader;
+import java.lang.ref.*;
+import java.nio.ByteBuffer;
+import java.util.Base64;
+import java.util.concurrent.atomic.*;
+
+public class Test2009 {
+ public static class Transform {
+ public Transform() {}
+ }
+ /*
+ * base64 encoded class/dex file for
+ *
+ * package art;
+ * public class Transform {
+ * public Transform() { }
+ * }
+ */
+ private static final byte[] DEX_BYTES_INITIAL =
+ Base64.getDecoder()
+ .decode(
+ "ZGV4CjAzNQBMYVKB9B8EiEj/K5pUWVbEqHPGshupr2RkAgAAcAAAAHhWNBIAAAAAAAAAANABAAAG"
+ + "AAAAcAAAAAMAAACIAAAAAQAAAJQAAAAAAAAAAAAAAAIAAACgAAAAAQAAALAAAACUAQAA0AAAAPAA"
+ + "AAD4AAAACQEAAB0BAAAtAQAAMAEAAAEAAAACAAAABAAAAAQAAAACAAAAAAAAAAAAAAAAAAAAAQAA"
+ + "AAAAAAAAAAAAAQAAAAEAAAAAAAAAAwAAAAAAAAC/AQAAAAAAAAEAAQABAAAA6AAAAAQAAABwEAEA"
+ + "AAAOAAMADjwAAAAABjxpbml0PgAPTGFydC9UcmFuc2Zvcm07ABJMamF2YS9sYW5nL09iamVjdDsA"
+ + "DlRyYW5zZm9ybS5qYXZhAAFWAIwBfn5EOHsiY29tcGlsYXRpb24tbW9kZSI6ImRlYnVnIiwiaGFz"
+ + "LWNoZWNrc3VtcyI6ZmFsc2UsIm1pbi1hcGkiOjEsInNoYS0xIjoiZDFkNTFjMWNiM2U4NWFhMzBl"
+ + "MDBhNjgyMmNjYTgzYmJlMWRmZTk0NSIsInZlcnNpb24iOiIyLjAuMTMtZGV2In0AAAABAACBgATQ"
+ + "AQAAAAAAAAAMAAAAAAAAAAEAAAAAAAAAAQAAAAYAAABwAAAAAgAAAAMAAACIAAAAAwAAAAEAAACU"
+ + "AAAABQAAAAIAAACgAAAABgAAAAEAAACwAAAAASAAAAEAAADQAAAAAyAAAAEAAADoAAAAAiAAAAYA"
+ + "AADwAAAAACAAAAEAAAC/AQAAAxAAAAEAAADMAQAAABAAAAEAAADQAQAA");
+
+ /*
+ * base64 encoded class/dex file for
+ * package art;
+ * public static class Transform {
+ * public String greeting;
+ * public static String static_greeting;
+ *
+ * public Transform() {
+ * greeting = "Hello";
+ * }
+ * public static String getGreetingStatic() {
+ * static_greeting = "static-meth";
+ * return static_greeting;
+ * }
+ * public String getGreeting() { greeting = "meth"; return greeting; }
+ * }
+ */
+ private static final byte[] DEX_BYTES =
+ Base64.getDecoder()
+ .decode(
+ "ZGV4CjAzNQB6kDahLt0Aoqc///gYs0Vgd/hpukfKc5mEAwAAcAAAAHhWNBIAAAAAAAAAAOQCAAAP"
+ + "AAAAcAAAAAQAAACsAAAAAgAAALwAAAACAAAA1AAAAAQAAADkAAAAAQAAAAQBAABgAgAAJAEAAIwB"
+ + "AACUAQAAmwEAAJ4BAACvAQAAwwEAANcBAADnAQAA6gEAAPcBAAAKAgAAFAIAABoCAAAnAgAAOAIA"
+ + "AAMAAAAEAAAABQAAAAcAAAACAAAAAgAAAAAAAAAHAAAAAwAAAAAAAAAAAAIACgAAAAAAAgANAAAA"
+ + "AAABAAAAAAAAAAAACAAAAAAAAAAJAAAAAQABAAAAAAAAAAAAAQAAAAEAAAAAAAAABgAAAAAAAADH"
+ + "AgAAAAAAAAIAAQAAAAAAhgEAAAUAAAAaAAsAWxAAABEAAAABAAAAAAAAAIIBAAAFAAAAGgAMAGkA"
+ + "AQARAAAAAgABAAEAAAB8AQAACAAAAHAQAwABABoAAQBbEAAADgAGAA48SwAJAA4ACgAOAAAABjxp"
+ + "bml0PgAFSGVsbG8AAUwAD0xhcnQvVHJhbnNmb3JtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2"
+ + "YS9sYW5nL1N0cmluZzsADlRyYW5zZm9ybS5qYXZhAAFWAAtnZXRHcmVldGluZwARZ2V0R3JlZXRp"
+ + "bmdTdGF0aWMACGdyZWV0aW5nAARtZXRoAAtzdGF0aWMtbWV0aAAPc3RhdGljX2dyZWV0aW5nAIwB"
+ + "fn5EOHsiY29tcGlsYXRpb24tbW9kZSI6ImRlYnVnIiwiaGFzLWNoZWNrc3VtcyI6ZmFsc2UsIm1p"
+ + "bi1hcGkiOjEsInNoYS0xIjoiZDFkNTFjMWNiM2U4NWFhMzBlMDBhNjgyMmNjYTgzYmJlMWRmZTk0"
+ + "NSIsInZlcnNpb24iOiIyLjAuMTMtZGV2In0AAQECAQEJAAEAgYAE3AICCcACAQGkAgAAAAAAAAAN"
+ + "AAAAAAAAAAEAAAAAAAAAAQAAAA8AAABwAAAAAgAAAAQAAACsAAAAAwAAAAIAAAC8AAAABAAAAAIA"
+ + "AADUAAAABQAAAAQAAADkAAAABgAAAAEAAAAEAQAAASAAAAMAAAAkAQAAAyAAAAMAAAB8AQAAAiAA"
+ + "AA8AAACMAQAAACAAAAEAAADHAgAAAxAAAAEAAADgAgAAABAAAAEAAADkAgAA");
+
+ public static void run() throws Exception {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest();
+ }
+
+ public static Class<?> MakeClass() throws Exception {
+ return new InMemoryDexClassLoader(
+ ByteBuffer.wrap(DEX_BYTES_INITIAL), Test2009.class.getClassLoader())
+ .loadClass("art.Transform");
+ }
+
+ public static void doTest() throws Exception {
+ // Make a transform
+ Class<?> ifields = MakeClass();
+ String res =
+ NativeLocalGetIField(
+ ifields.newInstance(),
+ () -> {
+ System.out.println("Doing redefinition for instance field");
+ Redefinition.doCommonStructuralClassRedefinition(ifields, DEX_BYTES);
+ });
+ System.out.println("Result was " + res);
+ Class<?> sfields = MakeClass();
+ res =
+ NativeLocalGetSField(
+ sfields.newInstance(),
+ () -> {
+ System.out.println("Doing redefinition for static field");
+ Redefinition.doCommonStructuralClassRedefinition(sfields, DEX_BYTES);
+ });
+ System.out.println("Result was " + res);
+ Class<?> imeths = MakeClass();
+ res =
+ NativeLocalCallVirtual(
+ imeths.newInstance(),
+ () -> {
+ System.out.println("Doing redefinition for instance method");
+ Redefinition.doCommonStructuralClassRedefinition(imeths, DEX_BYTES);
+ });
+ System.out.println("Result was " + res);
+ Class<?> smeths = MakeClass();
+ res =
+ NativeLocalCallStatic(
+ smeths.newInstance(),
+ () -> {
+ System.out.println("Doing redefinition for static method");
+ Redefinition.doCommonStructuralClassRedefinition(smeths, DEX_BYTES);
+ });
+ System.out.println("Result was " + res);
+ }
+
+ public static native String NativeLocalCallVirtual(Object t, Runnable thnk);
+
+ public static native String NativeLocalCallStatic(Object t, Runnable thnk);
+
+ public static native String NativeLocalGetIField(Object t, Runnable thnk);
+
+ public static native String NativeLocalGetSField(Object t, Runnable thnk);
+}
diff --git a/test/2009-structural-local-ref/src/Main.java b/test/2009-structural-local-ref/src/Main.java
new file mode 100644
index 0000000..89b8557
--- /dev/null
+++ b/test/2009-structural-local-ref/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ System.out.println("FAIL: Test is only for art!");
+ }
+}
diff --git a/test/Android.bp b/test/Android.bp
index d33d4bf..89538c6 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -371,6 +371,7 @@
"1975-hello-structural-transformation/structural_transform.cc",
"1976-hello-structural-static-methods/structural_transform_methods.cc",
"2005-pause-all-redefine-multithreaded/pause-all.cc",
+ "2009-structural-local-ref/local-ref.cc",
],
// Use NDK-compatible headers for ctstiagent.
header_libs: [