summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/004-SignalTest/expected.txt4
-rw-r--r--test/004-SignalTest/signaltest.cc42
-rw-r--r--test/115-native-bridge/nativebridge.cc30
-rw-r--r--test/616-cha-abstract/src/Main.java4
-rw-r--r--test/616-cha-interface-default/expected.txt1
-rw-r--r--test/616-cha-interface-default/info.txt2
-rw-r--r--test/616-cha-interface-default/multidex.jpp3
-rw-r--r--test/616-cha-interface-default/run18
-rw-r--r--test/616-cha-interface-default/src-multidex/Base.java41
-rw-r--r--test/616-cha-interface-default/src/Main.java176
-rw-r--r--test/616-cha-interface/expected.txt1
-rw-r--r--test/616-cha-interface/info.txt1
-rw-r--r--test/616-cha-interface/run18
-rw-r--r--test/616-cha-interface/src/Main.java173
-rw-r--r--test/616-cha-miranda/expected.txt1
-rw-r--r--test/616-cha-miranda/info.txt1
-rw-r--r--test/616-cha-miranda/run18
-rw-r--r--test/616-cha-miranda/src/Main.java163
-rw-r--r--test/616-cha-proxy-method-inline/expected.txt1
-rw-r--r--test/616-cha-proxy-method-inline/info.txt1
-rw-r--r--test/616-cha-proxy-method-inline/multidex.jpp3
-rw-r--r--test/616-cha-proxy-method-inline/run18
-rw-r--r--test/616-cha-proxy-method-inline/src-multidex/Foo.java19
-rw-r--r--test/616-cha-proxy-method-inline/src/Main.java70
-rw-r--r--test/644-checker-deopt/expected.txt0
-rw-r--r--test/644-checker-deopt/info.txt2
-rw-r--r--test/644-checker-deopt/profile2
-rw-r--r--test/644-checker-deopt/run17
-rw-r--r--test/644-checker-deopt/src/Main.java74
-rw-r--r--test/901-hello-ti-agent/basics.cc16
-rw-r--r--test/901-hello-ti-agent/expected.txt1
-rw-r--r--test/901-hello-ti-agent/src/Main.java4
-rw-r--r--test/931-agent-thread/agent_thread.cc3
-rw-r--r--test/981-dedup-original-dex/expected.txt0
-rw-r--r--test/981-dedup-original-dex/info.txt4
-rwxr-xr-xtest/981-dedup-original-dex/run17
-rw-r--r--test/981-dedup-original-dex/src/Main.java139
-rw-r--r--test/981-dedup-original-dex/src/Transform.java21
-rw-r--r--test/981-dedup-original-dex/src/Transform2.java21
-rw-r--r--test/982-ok-no-retransform/expected.txt2
-rw-r--r--test/982-ok-no-retransform/info.txt1
-rwxr-xr-xtest/982-ok-no-retransform/run17
-rw-r--r--test/982-ok-no-retransform/src/Main.java34
-rw-r--r--test/982-ok-no-retransform/src/Transform.java28
-rw-r--r--test/Android.run-test.mk17
-rw-r--r--test/knownfailures.json14
-rwxr-xr-xtest/testrunner/run_build_test_target.py8
-rwxr-xr-xtest/testrunner/testrunner.py27
-rw-r--r--test/ti-agent/common_load.cc2
49 files changed, 1210 insertions, 70 deletions
diff --git a/test/004-SignalTest/expected.txt b/test/004-SignalTest/expected.txt
index b3a0e1cbe0..847b56f823 100644
--- a/test/004-SignalTest/expected.txt
+++ b/test/004-SignalTest/expected.txt
@@ -3,4 +3,8 @@ init signal test
Caught NullPointerException
Caught StackOverflowError
signal caught
+unblocked signal received
+unblocking blocked signal
+blocked signal received
+signal handler done
Signal test OK
diff --git a/test/004-SignalTest/signaltest.cc b/test/004-SignalTest/signaltest.cc
index 6dd63551fd..a58a0752c9 100644
--- a/test/004-SignalTest/signaltest.cc
+++ b/test/004-SignalTest/signaltest.cc
@@ -18,13 +18,14 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/ucontext.h>
#include <unistd.h>
#include "base/macros.h"
static int signal_count;
-static const int kMaxSignal = 2;
+static const int kMaxSignal = 1;
#if defined(__i386__) || defined(__x86_64__)
#if defined(__APPLE__)
@@ -47,6 +48,17 @@ static const int kMaxSignal = 2;
#endif
#endif
+#define BLOCKED_SIGNAL SIGUSR1
+#define UNBLOCKED_SIGNAL SIGUSR2
+
+static void blocked_signal(int sig ATTRIBUTE_UNUSED) {
+ printf("blocked signal received\n");
+}
+
+static void unblocked_signal(int sig ATTRIBUTE_UNUSED) {
+ printf("unblocked signal received\n");
+}
+
static void signalhandler(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
void* context) {
printf("signal caught\n");
@@ -54,6 +66,16 @@ static void signalhandler(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UN
if (signal_count > kMaxSignal) {
abort();
}
+
+ raise(UNBLOCKED_SIGNAL);
+ raise(BLOCKED_SIGNAL);
+ printf("unblocking blocked signal\n");
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, BLOCKED_SIGNAL);
+ sigprocmask(SIG_UNBLOCK, &mask, nullptr);
+
#if defined(__arm__)
struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
@@ -71,6 +93,8 @@ static void signalhandler(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UN
#else
UNUSED(context);
#endif
+
+ printf("signal handler done\n");
}
static struct sigaction oldaction;
@@ -78,13 +102,21 @@ static struct sigaction oldaction;
extern "C" JNIEXPORT void JNICALL Java_Main_initSignalTest(JNIEnv*, jclass) {
struct sigaction action;
action.sa_sigaction = signalhandler;
- sigemptyset(&action.sa_mask);
+ sigfillset(&action.sa_mask);
+ sigdelset(&action.sa_mask, UNBLOCKED_SIGNAL);
action.sa_flags = SA_SIGINFO | SA_ONSTACK;
#if !defined(__APPLE__) && !defined(__mips__)
action.sa_restorer = nullptr;
#endif
sigaction(SIGSEGV, &action, &oldaction);
+ struct sigaction check;
+ sigaction(SIGSEGV, nullptr, &check);
+ if (memcmp(&action, &check, sizeof(action)) != 0) {
+ printf("sigaction returned different value\n");
+ }
+ signal(BLOCKED_SIGNAL, blocked_signal);
+ signal(UNBLOCKED_SIGNAL, unblocked_signal);
}
extern "C" JNIEXPORT void JNICALL Java_Main_terminateSignalTest(JNIEnv*, jclass) {
@@ -96,6 +128,12 @@ extern "C" JNIEXPORT void JNICALL Java_Main_terminateSignalTest(JNIEnv*, jclass)
char *go_away_compiler = nullptr;
extern "C" JNIEXPORT jint JNICALL Java_Main_testSignal(JNIEnv*, jclass) {
+ // Unblock UNBLOCKED_SIGNAL.
+ sigset_t mask;
+ memset(&mask, 0, sizeof(mask));
+ sigaddset(&mask, UNBLOCKED_SIGNAL);
+ sigprocmask(SIG_UNBLOCK, &mask, nullptr);
+
#if defined(__arm__) || defined(__i386__) || defined(__aarch64__)
// On supported architectures we cause a real SEGV.
*go_away_compiler = 'a';
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index 41329af138..f913cf69d0 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -395,20 +395,6 @@ extern "C" bool native_bridge_isCompatibleWith(uint32_t bridge_version ATTRIBUTE
#endif
#endif
-static bool cannot_be_blocked(int signum) {
- // These two sigs cannot be blocked anywhere.
- if ((signum == SIGKILL) || (signum == SIGSTOP)) {
- return true;
- }
-
- // The invalid rt_sig cannot be blocked.
- if (((signum >= 32) && (signum < SIGRTMIN)) || (signum > SIGRTMAX)) {
- return true;
- }
-
- return false;
-}
-
// A dummy special handler, continueing after the faulting location. This code comes from
// 004-SignalTest.
static bool nb_signalhandler(int sig, siginfo_t* info ATTRIBUTE_UNUSED, void* context) {
@@ -433,22 +419,6 @@ static bool nb_signalhandler(int sig, siginfo_t* info ATTRIBUTE_UNUSED, void* co
#endif
}
- // Before invoking this handler, all other unclaimed signals must be blocked.
- // We're trying to check the signal mask to verify its status here.
- sigset_t tmpset;
- sigemptyset(&tmpset);
- sigprocmask(SIG_SETMASK, nullptr, &tmpset);
- int other_claimed = (sig == SIGSEGV) ? SIGILL : SIGSEGV;
- for (int signum = 0; signum < NSIG; ++signum) {
- if (cannot_be_blocked(signum)) {
- continue;
- } else if ((sigismember(&tmpset, signum)) && (signum == other_claimed)) {
- printf("ERROR: The claimed signal %d is blocked\n", signum);
- } else if ((!sigismember(&tmpset, signum)) && (signum != other_claimed)) {
- printf("ERROR: The unclaimed signal %d is not blocked\n", signum);
- }
- }
-
// We handled this...
return true;
}
diff --git a/test/616-cha-abstract/src/Main.java b/test/616-cha-abstract/src/Main.java
index e1d7db170d..b33f575dec 100644
--- a/test/616-cha-abstract/src/Main.java
+++ b/test/616-cha-abstract/src/Main.java
@@ -39,8 +39,8 @@ class Main2 extends Main1 {
}
public class Main {
- static Main1 sMain1;
- static Main1 sMain2;
+ static Base sMain1;
+ static Base sMain2;
static boolean sIsOptimizing = true;
static boolean sHasJIT = true;
diff --git a/test/616-cha-interface-default/expected.txt b/test/616-cha-interface-default/expected.txt
new file mode 100644
index 0000000000..6a5618ebc6
--- /dev/null
+++ b/test/616-cha-interface-default/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/616-cha-interface-default/info.txt b/test/616-cha-interface-default/info.txt
new file mode 100644
index 0000000000..11baa1f0f2
--- /dev/null
+++ b/test/616-cha-interface-default/info.txt
@@ -0,0 +1,2 @@
+Test for Class Hierarchy Analysis (CHA) on interface method.
+Test it under multidex configuration to check cross-dex inlining.
diff --git a/test/616-cha-interface-default/multidex.jpp b/test/616-cha-interface-default/multidex.jpp
new file mode 100644
index 0000000000..b0d200ea38
--- /dev/null
+++ b/test/616-cha-interface-default/multidex.jpp
@@ -0,0 +1,3 @@
+Main:
+ @@com.android.jack.annotations.ForceInMainDex
+ class Main
diff --git a/test/616-cha-interface-default/run b/test/616-cha-interface-default/run
new file mode 100644
index 0000000000..d8b4f0d26c
--- /dev/null
+++ b/test/616-cha-interface-default/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 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.
+
+# Run without an app image to prevent the classes to be loaded at startup.
+exec ${RUN} "${@}" --no-app-image
diff --git a/test/616-cha-interface-default/src-multidex/Base.java b/test/616-cha-interface-default/src-multidex/Base.java
new file mode 100644
index 0000000000..2cbcb500c4
--- /dev/null
+++ b/test/616-cha-interface-default/src-multidex/Base.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+interface Base {
+ default public int foo(int i) {
+ if (i != 1) {
+ return -2;
+ }
+ return i + 10;
+ }
+
+ // Test default method that's not inlined.
+ default public int $noinline$bar() {
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ return -1;
+ }
+
+ default void printError(String msg) {
+ System.out.println(msg);
+ }
+}
diff --git a/test/616-cha-interface-default/src/Main.java b/test/616-cha-interface-default/src/Main.java
new file mode 100644
index 0000000000..951607d2cf
--- /dev/null
+++ b/test/616-cha-interface-default/src/Main.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+class Main1 implements Base {
+}
+
+class Main2 extends Main1 {
+ public void foobar() {}
+}
+
+class Main3 implements Base {
+ public int foo(int i) {
+ if (i != 3) {
+ printError("error3");
+ }
+ return -(i + 10);
+ }
+}
+
+public class Main {
+ static Base sMain1;
+ static Base sMain2;
+ static Base sMain3;
+
+ static boolean sIsOptimizing = true;
+ static boolean sHasJIT = true;
+ static volatile boolean sOtherThreadStarted;
+
+ private static void assertSingleImplementation(Class<?> clazz, String method_name, boolean b) {
+ if (hasSingleImplementation(clazz, method_name) != b) {
+ System.out.println(clazz + "." + method_name +
+ " doesn't have single implementation value of " + b);
+ }
+ }
+
+ static int getValue(Class<?> cls) {
+ if (cls == Main1.class || cls == Main2.class) {
+ return 1;
+ }
+ return 3;
+ }
+
+ // sMain1.foo()/sMain2.foo() will be always be Base.foo() before Main3 is loaded/linked.
+ // So sMain1.foo() can be devirtualized to Base.foo() and be inlined.
+ // After Dummy.createMain3() which links in Main3, live testImplement() on stack
+ // should be deoptimized.
+ static void testImplement(boolean createMain3, boolean wait, boolean setHasJIT) {
+ if (setHasJIT) {
+ if (isInterpreted()) {
+ sHasJIT = false;
+ }
+ return;
+ }
+
+ if (createMain3 && (sIsOptimizing || sHasJIT)) {
+ assertIsManaged();
+ }
+
+ if (sMain1.foo(getValue(sMain1.getClass())) != 11) {
+ System.out.println("11 expected.");
+ }
+ if (sMain1.$noinline$bar() != -1) {
+ System.out.println("-1 expected.");
+ }
+ if (sMain2.foo(getValue(sMain2.getClass())) != 11) {
+ System.out.println("11 expected.");
+ }
+
+ if (createMain3) {
+ // Wait for the other thread to start.
+ while (!sOtherThreadStarted);
+ // Create an Main2 instance and assign it to sMain2.
+ // sMain1 is kept the same.
+ sMain3 = Dummy.createMain3();
+ // Wake up the other thread.
+ synchronized(Main.class) {
+ Main.class.notify();
+ }
+ } else if (wait) {
+ // This is the other thread.
+ synchronized(Main.class) {
+ sOtherThreadStarted = true;
+ // Wait for Main2 to be linked and deoptimization is triggered.
+ try {
+ Main.class.wait();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ // There should be a deoptimization here right after Main3 is linked by
+ // calling Dummy.createMain3(), even though sMain1 didn't change.
+ // The behavior here would be different if inline-cache is used, which
+ // doesn't deoptimize since sMain1 still hits the type cache.
+ if (sMain1.foo(getValue(sMain1.getClass())) != 11) {
+ System.out.println("11 expected.");
+ }
+ if ((createMain3 || wait) && sHasJIT && !sIsOptimizing) {
+ // This method should be deoptimized right after Main3 is created.
+ assertIsInterpreted();
+ }
+
+ if (sMain3 != null) {
+ if (sMain3.foo(getValue(sMain3.getClass())) != -13) {
+ System.out.println("-13 expected.");
+ }
+ }
+ }
+
+ // Test scenarios under which CHA-based devirtualization happens,
+ // and class loading that implements a method can invalidate compiled code.
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+
+ if (isInterpreted()) {
+ sIsOptimizing = false;
+ }
+
+ // sMain1 is an instance of Main1.
+ // sMain2 is an instance of Main2.
+ // Neither Main1 nor Main2 override default method Base.foo().
+ // Main3 hasn't bee loaded yet.
+ sMain1 = new Main1();
+ sMain2 = new Main2();
+
+ ensureJitCompiled(Main.class, "testImplement");
+ testImplement(false, false, true);
+
+ if (sHasJIT && !sIsOptimizing) {
+ assertSingleImplementation(Base.class, "foo", true);
+ assertSingleImplementation(Main1.class, "foo", true);
+ } else {
+ // Main3 is verified ahead-of-time so it's linked in already.
+ }
+
+ // Create another thread that also calls sMain1.foo().
+ // Try to test suspend and deopt another thread.
+ new Thread() {
+ public void run() {
+ testImplement(false, true, false);
+ }
+ }.start();
+
+ // This will create Main3 instance in the middle of testImplement().
+ testImplement(true, false, false);
+ assertSingleImplementation(Base.class, "foo", false);
+ assertSingleImplementation(Main1.class, "foo", true);
+ assertSingleImplementation(sMain3.getClass(), "foo", true);
+ }
+
+ private static native void ensureJitCompiled(Class<?> itf, String method_name);
+ private static native void assertIsInterpreted();
+ private static native void assertIsManaged();
+ private static native boolean isInterpreted();
+ private static native boolean hasSingleImplementation(Class<?> clazz, String method_name);
+}
+
+// Put createMain3() in another class to avoid class loading due to verifier.
+class Dummy {
+ static Base createMain3() {
+ return new Main3();
+ }
+}
diff --git a/test/616-cha-interface/expected.txt b/test/616-cha-interface/expected.txt
new file mode 100644
index 0000000000..6a5618ebc6
--- /dev/null
+++ b/test/616-cha-interface/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/616-cha-interface/info.txt b/test/616-cha-interface/info.txt
new file mode 100644
index 0000000000..1fd330afd4
--- /dev/null
+++ b/test/616-cha-interface/info.txt
@@ -0,0 +1 @@
+Test for Class Hierarchy Analysis (CHA) on interface method.
diff --git a/test/616-cha-interface/run b/test/616-cha-interface/run
new file mode 100644
index 0000000000..d8b4f0d26c
--- /dev/null
+++ b/test/616-cha-interface/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 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.
+
+# Run without an app image to prevent the classes to be loaded at startup.
+exec ${RUN} "${@}" --no-app-image
diff --git a/test/616-cha-interface/src/Main.java b/test/616-cha-interface/src/Main.java
new file mode 100644
index 0000000000..3c9349663d
--- /dev/null
+++ b/test/616-cha-interface/src/Main.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+interface Base {
+ void foo(int i);
+ void $noinline$bar();
+}
+
+class Main1 implements Base {
+ public void foo(int i) {
+ if (i != 1) {
+ printError("error1");
+ }
+ }
+
+ // Test rewriting invoke-interface into invoke-virtual when inlining fails.
+ public void $noinline$bar() {
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ System.out.print("");
+ }
+
+ void printError(String msg) {
+ System.out.println(msg);
+ }
+}
+
+class Main2 extends Main1 {
+ public void foo(int i) {
+ if (i != 2) {
+ printError("error2");
+ }
+ }
+}
+
+public class Main {
+ static Base sMain1;
+ static Base sMain2;
+
+ static boolean sIsOptimizing = true;
+ static boolean sHasJIT = true;
+ static volatile boolean sOtherThreadStarted;
+
+ private static void assertSingleImplementation(Class<?> clazz, String method_name, boolean b) {
+ if (hasSingleImplementation(clazz, method_name) != b) {
+ System.out.println(clazz + "." + method_name +
+ " doesn't have single implementation value of " + b);
+ }
+ }
+
+ // sMain1.foo() will be always be Main1.foo() before Main2 is loaded/linked.
+ // So sMain1.foo() can be devirtualized to Main1.foo() and be inlined.
+ // After Dummy.createMain2() which links in Main2, live testImplement() on stack
+ // should be deoptimized.
+ static void testImplement(boolean createMain2, boolean wait, boolean setHasJIT) {
+ if (setHasJIT) {
+ if (isInterpreted()) {
+ sHasJIT = false;
+ }
+ return;
+ }
+
+ if (createMain2 && (sIsOptimizing || sHasJIT)) {
+ assertIsManaged();
+ }
+
+ sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2);
+ sMain1.$noinline$bar();
+
+ if (createMain2) {
+ // Wait for the other thread to start.
+ while (!sOtherThreadStarted);
+ // Create an Main2 instance and assign it to sMain2.
+ // sMain1 is kept the same.
+ sMain2 = Dummy.createMain2();
+ // Wake up the other thread.
+ synchronized(Main.class) {
+ Main.class.notify();
+ }
+ } else if (wait) {
+ // This is the other thread.
+ synchronized(Main.class) {
+ sOtherThreadStarted = true;
+ // Wait for Main2 to be linked and deoptimization is triggered.
+ try {
+ Main.class.wait();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ // There should be a deoptimization here right after Main2 is linked by
+ // calling Dummy.createMain2(), even though sMain1 didn't change.
+ // The behavior here would be different if inline-cache is used, which
+ // doesn't deoptimize since sMain1 still hits the type cache.
+ sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2);
+ if ((createMain2 || wait) && sHasJIT && !sIsOptimizing) {
+ // This method should be deoptimized right after Main2 is created.
+ assertIsInterpreted();
+ }
+
+ if (sMain2 != null) {
+ sMain2.foo(sMain2.getClass() == Main1.class ? 1 : 2);
+ }
+ }
+
+ // Test scenarios under which CHA-based devirtualization happens,
+ // and class loading that overrides a method can invalidate compiled code.
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+
+ if (isInterpreted()) {
+ sIsOptimizing = false;
+ }
+
+ // sMain1 is an instance of Main1. Main2 hasn't bee loaded yet.
+ sMain1 = new Main1();
+
+ ensureJitCompiled(Main.class, "testImplement");
+ testImplement(false, false, true);
+
+ if (sHasJIT && !sIsOptimizing) {
+ assertSingleImplementation(Base.class, "foo", true);
+ assertSingleImplementation(Main1.class, "foo", true);
+ } else {
+ // Main2 is verified ahead-of-time so it's linked in already.
+ }
+
+ // Create another thread that also calls sMain1.foo().
+ // Try to test suspend and deopt another thread.
+ new Thread() {
+ public void run() {
+ testImplement(false, true, false);
+ }
+ }.start();
+
+ // This will create Main2 instance in the middle of testImplement().
+ testImplement(true, false, false);
+ assertSingleImplementation(Base.class, "foo", false);
+ assertSingleImplementation(Main1.class, "foo", false);
+ }
+
+ private static native void ensureJitCompiled(Class<?> itf, String method_name);
+ private static native void assertIsInterpreted();
+ private static native void assertIsManaged();
+ private static native boolean isInterpreted();
+ private static native boolean hasSingleImplementation(Class<?> clazz, String method_name);
+}
+
+// Put createMain2() in another class to avoid class loading due to verifier.
+class Dummy {
+ static Main1 createMain2() {
+ return new Main2();
+ }
+}
diff --git a/test/616-cha-miranda/expected.txt b/test/616-cha-miranda/expected.txt
new file mode 100644
index 0000000000..6a5618ebc6
--- /dev/null
+++ b/test/616-cha-miranda/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/616-cha-miranda/info.txt b/test/616-cha-miranda/info.txt
new file mode 100644
index 0000000000..c46f33f613
--- /dev/null
+++ b/test/616-cha-miranda/info.txt
@@ -0,0 +1 @@
+Test for Class Hierarchy Analysis (CHA) on miranda method.
diff --git a/test/616-cha-miranda/run b/test/616-cha-miranda/run
new file mode 100644
index 0000000000..d8b4f0d26c
--- /dev/null
+++ b/test/616-cha-miranda/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 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.
+
+# Run without an app image to prevent the classes to be loaded at startup.
+exec ${RUN} "${@}" --no-app-image
diff --git a/test/616-cha-miranda/src/Main.java b/test/616-cha-miranda/src/Main.java
new file mode 100644
index 0000000000..e548482eb3
--- /dev/null
+++ b/test/616-cha-miranda/src/Main.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+interface Iface {
+ public void foo(int i);
+}
+
+abstract class Base implements Iface {
+ // Iface.foo(int) will be added as a miranda method.
+
+ void printError(String msg) {
+ System.out.println(msg);
+ }
+}
+
+class Main1 extends Base {
+ public void foo(int i) {
+ if (i != 1) {
+ printError("error1");
+ }
+ }
+}
+
+class Main2 extends Main1 {
+ public void foo(int i) {
+ if (i != 2) {
+ printError("error2");
+ }
+ }
+}
+
+public class Main {
+ static Base sMain1;
+ static Base sMain2;
+
+ static boolean sIsOptimizing = true;
+ static boolean sHasJIT = true;
+ static volatile boolean sOtherThreadStarted;
+
+ private static void assertSingleImplementation(Class<?> clazz, String method_name, boolean b) {
+ if (hasSingleImplementation(clazz, method_name) != b) {
+ System.out.println(clazz + "." + method_name +
+ " doesn't have single implementation value of " + b);
+ }
+ }
+
+ // sMain1.foo() will be always be Main1.foo() before Main2 is loaded/linked.
+ // So sMain1.foo() can be devirtualized to Main1.foo() and be inlined.
+ // After Dummy.createMain2() which links in Main2, live testOverride() on stack
+ // should be deoptimized.
+ static void testOverride(boolean createMain2, boolean wait, boolean setHasJIT) {
+ if (setHasJIT) {
+ if (isInterpreted()) {
+ sHasJIT = false;
+ }
+ return;
+ }
+
+ if (createMain2 && (sIsOptimizing || sHasJIT)) {
+ assertIsManaged();
+ }
+
+ sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2);
+
+ if (createMain2) {
+ // Wait for the other thread to start.
+ while (!sOtherThreadStarted);
+ // Create an Main2 instance and assign it to sMain2.
+ // sMain1 is kept the same.
+ sMain2 = Dummy.createMain2();
+ // Wake up the other thread.
+ synchronized(Main.class) {
+ Main.class.notify();
+ }
+ } else if (wait) {
+ // This is the other thread.
+ synchronized(Main.class) {
+ sOtherThreadStarted = true;
+ // Wait for Main2 to be linked and deoptimization is triggered.
+ try {
+ Main.class.wait();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ // There should be a deoptimization here right after Main2 is linked by
+ // calling Dummy.createMain2(), even though sMain1 didn't change.
+ // The behavior here would be different if inline-cache is used, which
+ // doesn't deoptimize since sMain1 still hits the type cache.
+ sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2);
+ if ((createMain2 || wait) && sHasJIT && !sIsOptimizing) {
+ // This method should be deoptimized right after Main2 is created.
+ assertIsInterpreted();
+ }
+
+ if (sMain2 != null) {
+ sMain2.foo(sMain2.getClass() == Main1.class ? 1 : 2);
+ }
+ }
+
+ // Test scenarios under which CHA-based devirtualization happens,
+ // and class loading that overrides a method can invalidate compiled code.
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+
+ if (isInterpreted()) {
+ sIsOptimizing = false;
+ }
+
+ // sMain1 is an instance of Main1. Main2 hasn't bee loaded yet.
+ sMain1 = new Main1();
+
+ ensureJitCompiled(Main.class, "testOverride");
+ testOverride(false, false, true);
+
+ if (sHasJIT && !sIsOptimizing) {
+ assertSingleImplementation(Base.class, "foo", true);
+ assertSingleImplementation(Main1.class, "foo", true);
+ } else {
+ // Main2 is verified ahead-of-time so it's linked in already.
+ }
+
+ // Create another thread that also calls sMain1.foo().
+ // Try to test suspend and deopt another thread.
+ new Thread() {
+ public void run() {
+ testOverride(false, true, false);
+ }
+ }.start();
+
+ // This will create Main2 instance in the middle of testOverride().
+ testOverride(true, false, false);
+ assertSingleImplementation(Base.class, "foo", false);
+ assertSingleImplementation(Main1.class, "foo", false);
+ }
+
+ private static native void ensureJitCompiled(Class<?> itf, String method_name);
+ private static native void assertIsInterpreted();
+ private static native void assertIsManaged();
+ private static native boolean isInterpreted();
+ private static native boolean hasSingleImplementation(Class<?> clazz, String method_name);
+}
+
+// Put createMain2() in another class to avoid class loading due to verifier.
+class Dummy {
+ static Main1 createMain2() {
+ return new Main2();
+ }
+}
diff --git a/test/616-cha-proxy-method-inline/expected.txt b/test/616-cha-proxy-method-inline/expected.txt
new file mode 100644
index 0000000000..6a5618ebc6
--- /dev/null
+++ b/test/616-cha-proxy-method-inline/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/616-cha-proxy-method-inline/info.txt b/test/616-cha-proxy-method-inline/info.txt
new file mode 100644
index 0000000000..012685547c
--- /dev/null
+++ b/test/616-cha-proxy-method-inline/info.txt
@@ -0,0 +1 @@
+Test for Class Hierarchy Analysis (CHA) on inlining a cross-dex proxy method.
diff --git a/test/616-cha-proxy-method-inline/multidex.jpp b/test/616-cha-proxy-method-inline/multidex.jpp
new file mode 100644
index 0000000000..b0d200ea38
--- /dev/null
+++ b/test/616-cha-proxy-method-inline/multidex.jpp
@@ -0,0 +1,3 @@
+Main:
+ @@com.android.jack.annotations.ForceInMainDex
+ class Main
diff --git a/test/616-cha-proxy-method-inline/run b/test/616-cha-proxy-method-inline/run
new file mode 100644
index 0000000000..d8b4f0d26c
--- /dev/null
+++ b/test/616-cha-proxy-method-inline/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 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.
+
+# Run without an app image to prevent the classes to be loaded at startup.
+exec ${RUN} "${@}" --no-app-image
diff --git a/test/616-cha-proxy-method-inline/src-multidex/Foo.java b/test/616-cha-proxy-method-inline/src-multidex/Foo.java
new file mode 100644
index 0000000000..9deca3e646
--- /dev/null
+++ b/test/616-cha-proxy-method-inline/src-multidex/Foo.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+interface Foo {
+ public Object bar(Object obj);
+}
diff --git a/test/616-cha-proxy-method-inline/src/Main.java b/test/616-cha-proxy-method-inline/src/Main.java
new file mode 100644
index 0000000000..be7bc820b3
--- /dev/null
+++ b/test/616-cha-proxy-method-inline/src/Main.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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.Method;
+import java.lang.reflect.InvocationTargetException;
+
+class DebugProxy implements java.lang.reflect.InvocationHandler {
+ private Object obj;
+ static Class<?>[] interfaces = {Foo.class};
+
+ public static Object newInstance(Object obj) {
+ return java.lang.reflect.Proxy.newProxyInstance(
+ Foo.class.getClassLoader(),
+ interfaces,
+ new DebugProxy(obj));
+ }
+
+ private DebugProxy(Object obj) {
+ this.obj = obj;
+ }
+
+ public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
+ Object result;
+ if (obj == null) {
+ return null;
+ }
+ try {
+ System.out.println("before invoking method " + m.getName());
+ result = m.invoke(obj, args);
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ } catch (Exception e) {
+ throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
+ } finally {
+ System.out.println("after invoking method " + m.getName());
+ }
+ return result;
+ }
+}
+
+public class Main {
+ public static void call(Foo foo) {
+ if (foo == null) {
+ return;
+ }
+ foo.bar(null);
+ }
+
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+ Foo foo = (Foo)DebugProxy.newInstance(null);
+ ensureJitCompiled(Main.class, "call");
+ call(foo);
+ }
+
+ private static native void ensureJitCompiled(Class<?> itf, String method_name);
+}
diff --git a/test/644-checker-deopt/expected.txt b/test/644-checker-deopt/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/644-checker-deopt/expected.txt
diff --git a/test/644-checker-deopt/info.txt b/test/644-checker-deopt/info.txt
new file mode 100644
index 0000000000..c5fb12c570
--- /dev/null
+++ b/test/644-checker-deopt/info.txt
@@ -0,0 +1,2 @@
+Regression test for making sure HDeoptimize is executed before
+the code it should have prevented executing.
diff --git a/test/644-checker-deopt/profile b/test/644-checker-deopt/profile
new file mode 100644
index 0000000000..cb261cc694
--- /dev/null
+++ b/test/644-checker-deopt/profile
@@ -0,0 +1,2 @@
+LMain;->inlineMonomorphic(LMain;)I+LMain;
+LMain;->inlinePolymorphic(LMain;)I+LMain;,LSubMain;
diff --git a/test/644-checker-deopt/run b/test/644-checker-deopt/run
new file mode 100644
index 0000000000..146e180000
--- /dev/null
+++ b/test/644-checker-deopt/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 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.
+
+exec ${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile
diff --git a/test/644-checker-deopt/src/Main.java b/test/644-checker-deopt/src/Main.java
new file mode 100644
index 0000000000..17c80a6057
--- /dev/null
+++ b/test/644-checker-deopt/src/Main.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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 {
+
+ /// CHECK-START: int Main.inlineMonomorphic(Main) inliner (before)
+ /// CHECK: InvokeVirtual method_name:Main.getValue
+
+ /// CHECK-START: int Main.inlineMonomorphic(Main) inliner (after)
+ /// CHECK-NOT: InvokeVirtual method_name:Main.getValue
+
+ /// CHECK-START: int Main.inlineMonomorphic(Main) licm (before)
+ /// CHECK: <<Deopt:l\d+>> Deoptimize
+ /// CHECK: InstanceFieldGet [<<Deopt>>] field_name:Main.value
+
+ /// CHECK-START: int Main.inlineMonomorphic(Main) licm (after)
+ /// CHECK: <<Deopt:l\d+>> Deoptimize
+ /// CHECK: InstanceFieldGet [<<Deopt>>] field_name:Main.value
+
+ public static int inlineMonomorphic(Main a) {
+ if (a == null) {
+ return 42;
+ }
+ int i = 0;
+ while (i < 100) {
+ i += a.getValue();
+ }
+ return i;
+ }
+
+ /// CHECK-START: int Main.inlinePolymorphic(Main) inliner (before)
+ /// CHECK: InvokeVirtual method_name:Main.getValue
+
+ /// CHECK-START: int Main.inlinePolymorphic(Main) inliner (after)
+ /// CHECK-NOT: InvokeVirtual method_name:Main.getValue
+
+ /// CHECK-START: int Main.inlineMonomorphic(Main) licm (before)
+ /// CHECK: <<Deopt:l\d+>> Deoptimize
+ /// CHECK: InstanceFieldGet [<<Deopt>>] field_name:Main.value
+
+ /// CHECK-START: int Main.inlineMonomorphic(Main) licm (after)
+ /// CHECK: <<Deopt:l\d+>> Deoptimize
+ /// CHECK: InstanceFieldGet [<<Deopt>>] field_name:Main.value
+ public static int inlinePolymorphic(Main a) {
+ return a.getValue();
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static void main(String[] args) {
+ inlineMonomorphic(new Main());
+ }
+
+ int value = 1;
+}
+
+// Add a subclass of 'Main' to write the polymorphic inline cache in the profile.
+class SubMain extends Main {
+}
diff --git a/test/901-hello-ti-agent/basics.cc b/test/901-hello-ti-agent/basics.cc
index 91662770be..cbd768663b 100644
--- a/test/901-hello-ti-agent/basics.cc
+++ b/test/901-hello-ti-agent/basics.cc
@@ -16,6 +16,8 @@
#include "901-hello-ti-agent/basics.h"
+#include <thread>
+
#include <jni.h>
#include <stdio.h>
#include <string.h>
@@ -159,5 +161,19 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkLivePhase(
return (current_phase == JVMTI_PHASE_LIVE) ? JNI_TRUE : JNI_FALSE;
}
+static void CallJvmtiFunction(jvmtiEnv* env, jclass klass, jvmtiError* err) {
+ jint n;
+ jmethodID* methods = nullptr;
+ *err = env->GetClassMethods(klass, &n, &methods);
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkUnattached(
+ JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass) {
+ jvmtiError res = JVMTI_ERROR_NONE;
+ std::thread t1(CallJvmtiFunction, jvmti_env, Main_klass, &res);
+ t1.join();
+ return res == JVMTI_ERROR_UNATTACHED_THREAD;
+}
+
} // namespace Test901HelloTi
} // namespace art
diff --git a/test/901-hello-ti-agent/expected.txt b/test/901-hello-ti-agent/expected.txt
index c4b24cba90..eb5b6a2f93 100644
--- a/test/901-hello-ti-agent/expected.txt
+++ b/test/901-hello-ti-agent/expected.txt
@@ -3,6 +3,7 @@ VMStart
VMInit
Hello, world!
Agent in live phase.
+Received expected error for unattached JVMTI calls
0
1
2
diff --git a/test/901-hello-ti-agent/src/Main.java b/test/901-hello-ti-agent/src/Main.java
index 4d62ed3f5d..556e05b5d0 100644
--- a/test/901-hello-ti-agent/src/Main.java
+++ b/test/901-hello-ti-agent/src/Main.java
@@ -21,6 +21,9 @@ public class Main {
if (checkLivePhase()) {
System.out.println("Agent in live phase.");
}
+ if (checkUnattached()) {
+ System.out.println("Received expected error for unattached JVMTI calls");
+ }
set(0); // OTHER
set(1); // GC
@@ -41,4 +44,5 @@ public class Main {
private static native boolean checkLivePhase();
private static native void setVerboseFlag(int flag, boolean value);
+ private static native boolean checkUnattached();
}
diff --git a/test/931-agent-thread/agent_thread.cc b/test/931-agent-thread/agent_thread.cc
index f8f9e48657..2e6bd46f4e 100644
--- a/test/931-agent-thread/agent_thread.cc
+++ b/test/931-agent-thread/agent_thread.cc
@@ -36,7 +36,8 @@ namespace Test930AgentThread {
struct AgentData {
AgentData() : main_thread(nullptr),
jvmti_env(nullptr),
- b(2) {
+ b(2),
+ priority(0) {
}
jthread main_thread;
diff --git a/test/981-dedup-original-dex/expected.txt b/test/981-dedup-original-dex/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/981-dedup-original-dex/expected.txt
diff --git a/test/981-dedup-original-dex/info.txt b/test/981-dedup-original-dex/info.txt
new file mode 100644
index 0000000000..62696e00d7
--- /dev/null
+++ b/test/981-dedup-original-dex/info.txt
@@ -0,0 +1,4 @@
+Tests basic functions in the jvmti plugin.
+
+This checks that we do not needlessly duplicate the contents of retransformed
+classes original dex files.
diff --git a/test/981-dedup-original-dex/run b/test/981-dedup-original-dex/run
new file mode 100755
index 0000000000..e92b873956
--- /dev/null
+++ b/test/981-dedup-original-dex/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2017 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
diff --git a/test/981-dedup-original-dex/src/Main.java b/test/981-dedup-original-dex/src/Main.java
new file mode 100644
index 0000000000..cd3f007532
--- /dev/null
+++ b/test/981-dedup-original-dex/src/Main.java
@@ -0,0 +1,139 @@
+/*
+ * 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.Base64;
+
+import dalvik.system.ClassExt;
+
+public class Main {
+
+ /**
+ * base64 encoded class/dex file for
+ * class Transform {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static final byte[] DEX_BYTES_1 = Base64.getDecoder().decode(
+ "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
+ "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
+ "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
+ "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+ "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
+ "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
+ "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
+ "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
+ "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" +
+ "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
+ "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
+ "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
+ "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
+
+ /**
+ * base64 encoded class/dex file for
+ * class Transform2 {
+ * public void sayHi() {
+ * System.out.println("Goodbye2");
+ * }
+ * }
+ */
+ private static final byte[] DEX_BYTES_2 = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAjXDED2iflQ3NXbPtBRVjQVMqoDU9nDz/QAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" +
+ "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" +
+ "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" +
+ "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+ "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" +
+ "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" +
+ "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTIADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJp" +
+ "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" +
+ "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" +
+ "A291dAAHcHJpbnRsbgAFc2F5SGkAAQAHDgADAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" +
+ "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" +
+ "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" +
+ "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA");
+
+ public static void main(String[] args) {
+ try {
+ doTest();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void assertSame(Object a, Object b) throws Exception {
+ if (a != b) {
+ throw new AssertionError("'" + (a != null ? a.toString() : "null") + "' is not the same as " +
+ "'" + (b != null ? b.toString() : "null") + "'");
+ }
+ }
+
+ private static Object getObjectField(Object o, String name) throws Exception {
+ return getObjectField(o, o.getClass(), name);
+ }
+
+ private static Object getObjectField(Object o, Class<?> type, String name) throws Exception {
+ Field f = type.getDeclaredField(name);
+ f.setAccessible(true);
+ return f.get(o);
+ }
+
+ private static Object getOriginalDexFile(Class<?> k) throws Exception {
+ ClassExt ext_data_object = (ClassExt) getObjectField(k, "extData");
+ if (ext_data_object == null) {
+ return null;
+ }
+
+ return getObjectField(ext_data_object, "originalDexFile");
+ }
+
+ public static void doTest() throws Exception {
+ // Make sure both of these are loaded prior to transformations being added so they have the same
+ // original dex files.
+ Transform t1 = new Transform();
+ Transform2 t2 = new Transform2();
+
+ assertSame(null, getOriginalDexFile(t1.getClass()));
+ assertSame(null, getOriginalDexFile(t2.getClass()));
+ assertSame(null, getOriginalDexFile(Main.class));
+
+ addCommonTransformationResult("Transform", new byte[0], DEX_BYTES_1);
+ addCommonTransformationResult("Transform2", new byte[0], DEX_BYTES_2);
+ enableCommonRetransformation(true);
+ doCommonClassRetransformation(Transform.class, Transform2.class);
+
+ assertSame(getOriginalDexFile(t1.getClass()), getOriginalDexFile(t2.getClass()));
+ assertSame(null, getOriginalDexFile(Main.class));
+ // Make sure that the original dex file is a DexCache object.
+ assertSame(getOriginalDexFile(t1.getClass()).getClass(), Class.forName("java.lang.DexCache"));
+
+ // Check that we end up with a byte[] if we do a direct RedefineClasses
+ enableCommonRetransformation(false);
+ doCommonClassRedefinition(Transform.class, new byte[0], DEX_BYTES_1);
+ assertSame((new byte[0]).getClass(), getOriginalDexFile(t1.getClass()).getClass());
+ }
+
+ // Transforms the class
+ private static native void doCommonClassRetransformation(Class<?>... target);
+ private static native void doCommonClassRedefinition(Class<?> target,
+ byte[] class_file,
+ byte[] dex_file);
+ private static native void enableCommonRetransformation(boolean enable);
+ private static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/981-dedup-original-dex/src/Transform.java b/test/981-dedup-original-dex/src/Transform.java
new file mode 100644
index 0000000000..3c97907ddc
--- /dev/null
+++ b/test/981-dedup-original-dex/src/Transform.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+class Transform {
+ public void sayHi() {
+ System.out.println("hello");
+ }
+}
diff --git a/test/981-dedup-original-dex/src/Transform2.java b/test/981-dedup-original-dex/src/Transform2.java
new file mode 100644
index 0000000000..eb22842184
--- /dev/null
+++ b/test/981-dedup-original-dex/src/Transform2.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+class Transform2 {
+ public void sayHi() {
+ System.out.println("hello2");
+ }
+}
diff --git a/test/982-ok-no-retransform/expected.txt b/test/982-ok-no-retransform/expected.txt
new file mode 100644
index 0000000000..317e9677c3
--- /dev/null
+++ b/test/982-ok-no-retransform/expected.txt
@@ -0,0 +1,2 @@
+hello
+hello
diff --git a/test/982-ok-no-retransform/info.txt b/test/982-ok-no-retransform/info.txt
new file mode 100644
index 0000000000..875a5f6ec1
--- /dev/null
+++ b/test/982-ok-no-retransform/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/982-ok-no-retransform/run b/test/982-ok-no-retransform/run
new file mode 100755
index 0000000000..c6e62ae6cd
--- /dev/null
+++ b/test/982-ok-no-retransform/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
diff --git a/test/982-ok-no-retransform/src/Main.java b/test/982-ok-no-retransform/src/Main.java
new file mode 100644
index 0000000000..7bb4a46155
--- /dev/null
+++ b/test/982-ok-no-retransform/src/Main.java
@@ -0,0 +1,34 @@
+/*
+ * 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.util.Base64;
+public class Main {
+
+ public static void main(String[] args) {
+ doTest(new Transform());
+ }
+
+ public static void doTest(Transform t) {
+ t.sayHi();
+ enableCommonRetransformation(true);
+ doCommonClassRetransformation(Transform.class);
+ t.sayHi();
+ }
+
+ // Transforms the class
+ private static native void doCommonClassRetransformation(Class<?>... target);
+ private static native void enableCommonRetransformation(boolean enable);
+}
diff --git a/test/982-ok-no-retransform/src/Transform.java b/test/982-ok-no-retransform/src/Transform.java
new file mode 100644
index 0000000000..8e8af355da
--- /dev/null
+++ b/test/982-ok-no-retransform/src/Transform.java
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+class Transform {
+ public void sayHi() {
+ // Use lower 'h' to make sure the string will have a different string id
+ // than the transformation (the transformation code is the same except
+ // the actual printed String, which was making the test inacurately passing
+ // in JIT mode when loading the string from the dex cache, as the string ids
+ // of the two different strings were the same).
+ // We know the string ids will be different because lexicographically:
+ // "Goodbye" < "LTransform;" < "hello".
+ System.out.println("hello");
+ }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 703b911f0f..cc015b031d 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -138,6 +138,7 @@ TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/conscrypt-testdex.jar
# specific version depending on the compiler.
ART_TEST_HOST_RUN_TEST_DEPENDENCIES := \
$(ART_HOST_EXECUTABLES) \
+ $(HOST_OUT_EXECUTABLES)/hprof-conv \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtiagent) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtiagentd) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libartagent) \
@@ -177,8 +178,6 @@ host_prereq_rules += $(HOST_JACK_CLASSPATH_DEPENDENCIES)
# Required for dx, jasmin, smali, dexmerger, jack.
host_prereq_rules += $(TEST_ART_RUN_TEST_DEPENDENCIES)
-host_prereq_rules += $(HOST_OUT_EXECUTABLES)/hprof-conv
-
# Classpath for Jack compilation for target.
target_prereq_rules := $(TARGET_JACK_CLASSPATH_DEPENDENCIES)
@@ -225,18 +224,6 @@ test-art-host-run-test-dependencies : $(host_prereq_rules)
test-art-target-run-test-dependencies : $(target_prereq_rules)
test-art-run-test-dependencies : test-art-host-run-test-dependencies test-art-target-run-test-dependencies
-# Generate list of dependencies required for given target - HOST or TARGET, IMAGE_TYPE,
-# COMPILER_TYPE and ADDRESS_SIZE.
-$(foreach target, $(TARGET_TYPES), \
- $(foreach image, $(IMAGE_TYPES), \
- $(foreach compiler, $(COMPILER_TYPES), \
- $(foreach address_size, $(ALL_ADDRESS_SIZES), $(eval \
- $(call core-image-dependencies,$(target),$(image),$(compiler),$(address_size)))))))
-
-test-art-host-run-test-dependencies : $(host_prereq_rules)
-test-art-target-run-test-dependencies : $(target_prereq_rules)
-test-art-run-test-dependencies : test-art-host-run-test-dependencies test-art-target-run-test-dependencies
-
# Create a rule to build and run a test group of the following form:
# test-art-{1: host target}-run-test
define define-test-art-host-or-target-run-test-group
@@ -259,8 +246,6 @@ host_prereq_rules :=
target_prereq_rules :=
core-image-dependencies :=
name-to-var :=
-ART_TEST_HOST_RUN_TEST_DEPENDENCIES :=
-TEST_ART_TARGET_SYNC_DEPS :=
define-test-art-host-or-target-run-test-group :=
TARGET_TYPES :=
COMPILER_TYPES :=
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 2de34ca44f..8aa0c55839 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -332,8 +332,12 @@
{
"tests": ["912-classes",
"616-cha",
- "616-cha-abstract"],
- "bug": "http://b/36344364 http://b36344221",
+ "616-cha-abstract",
+ "616-cha-interface",
+ "616-cha-interface-default",
+ "616-cha-miranda",
+ "616-cha-proxy-method-inline"],
+ "bug": "http://b/36344364 http://b/36344221",
"variant": "no-dex2oat | relocate-npatchoat"
},
{
@@ -358,9 +362,9 @@
"variant": "interp-ac"
},
{
- "tests": "638-checker-inline-caches",
- "description": ["Disable 638-checker-inline-caches temporarily until a fix",
- "arrives."],
+ "tests": ["638-checker-inline-caches",
+ "644-checker-deopt"],
+ "description": ["Disabled temporarily until a fix arrives."],
"bug": "http://b/36371709"
}
]
diff --git a/test/testrunner/run_build_test_target.py b/test/testrunner/run_build_test_target.py
index 835b678cd6..282ac484b6 100755
--- a/test/testrunner/run_build_test_target.py
+++ b/test/testrunner/run_build_test_target.py
@@ -51,7 +51,10 @@ if target.get('target'):
build_command += ' -j' + str(n_threads)
build_command += ' -C ' + env.ANDROID_BUILD_TOP
build_command += ' ' + target.get('target')
- print build_command.split()
+ # Add 'dist' to avoid Jack issues b/36169180.
+ build_command += ' dist'
+ sys.stdout.write(str(build_command))
+ sys.stdout.flush()
if subprocess.call(build_command.split()):
sys.exit(1)
@@ -64,7 +67,8 @@ if target.get('run-tests'):
run_test_command += ['--host']
run_test_command += ['--verbose']
- print run_test_command
+ sys.stdout.write(str(run_test_command))
+ sys.stdout.flush()
if subprocess.call(run_test_command):
sys.exit(1)
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index 3203f7ad84..149578d9ed 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -53,6 +53,7 @@ import os
import re
import subprocess
import sys
+import tempfile
import threading
import time
@@ -433,8 +434,10 @@ def run_tests(tests):
options_test += ' --instruction-set-features ' + \
env.HOST_2ND_ARCH_PREFIX_DEX2OAT_HOST_INSTRUCTION_SET_FEATURES
- options_test = (' --output-path %s/run-test-output/%s') % (
- env.ART_HOST_TEST_DIR, test_name) + options_test
+ # TODO(http://36039166): This is a temporary solution to
+ # fix build breakages.
+ options_test = (' --output-path %s') % (
+ tempfile.mkdtemp(dir=env.ART_HOST_TEST_DIR)) + options_test
run_test_sh = env.ANDROID_BUILD_TOP + '/art/test/run-test'
command = run_test_sh + ' ' + options_test + ' ' + test
@@ -480,7 +483,7 @@ def run_test(command, test, test_variant, test_name):
if test_passed:
print_test_info(test_name, 'PASS')
else:
- failed_tests.append(test_name)
+ failed_tests.append((test_name, script_output))
if not env.ART_TEST_KEEP_GOING:
stop_testrunner = True
print_test_info(test_name, 'FAIL', ('%s\n%s') % (
@@ -491,13 +494,13 @@ def run_test(command, test, test_variant, test_name):
else:
print_test_info(test_name, '')
except subprocess.TimeoutExpired as e:
- failed_tests.append(test_name)
- print_test_info(test_name, 'TIMEOUT', 'timed out in %d\n%s' % (
+ failed_tests.append((test_name, 'Timed out in %d seconds'))
+ print_test_info(test_name, 'TIMEOUT', 'Timed out in %d seconds\n%s' % (
timeout, command))
except Exception as e:
- failed_tests.append(test_name)
- print_test_info(test_name, 'FAIL')
- print_text(('%s\n%s\n\n') % (command, str(e)))
+ failed_tests.append((test_name, str(e)))
+ print_test_info(test_name, 'FAIL',
+ ('%s\n%s\n\n') % (command, str(e)))
finally:
semaphore.release()
@@ -711,16 +714,16 @@ def print_analysis():
# Prints the list of skipped tests, if any.
if skipped_tests:
- print_text(COLOR_SKIP + 'SKIPPED TESTS' + COLOR_NORMAL + '\n')
+ print_text(COLOR_SKIP + 'SKIPPED TESTS: ' + COLOR_NORMAL + '\n')
for test in skipped_tests:
print_text(test + '\n')
print_text('\n')
# Prints the list of failed tests, if any.
if failed_tests:
- print_text(COLOR_ERROR + 'FAILED TESTS' + COLOR_NORMAL + '\n')
- for test in failed_tests:
- print_text(test + '\n')
+ print_text(COLOR_ERROR + 'FAILED: ' + COLOR_NORMAL + '\n')
+ for test_info in failed_tests:
+ print_text(('%s\n%s\n' % (test_info[0], test_info[1])))
def parse_test_name(test_name):
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index fddae3af02..68c7d50dbc 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -121,6 +121,8 @@ static AgentLib agents[] = {
{ "943-private-recursive-jit", common_redefine::OnLoad, nullptr },
{ "944-transform-classloaders", common_redefine::OnLoad, nullptr },
{ "945-obsolete-native", common_redefine::OnLoad, nullptr },
+ { "981-dedup-original-dex", common_retransform::OnLoad, nullptr },
+ { "982-ok-no-retransform", common_retransform::OnLoad, nullptr },
};
static AgentLib* FindAgent(char* name) {