From 2e410d259780671752445529551968512fd3cf8e Mon Sep 17 00:00:00 2001 From: Alex Light Date: Thu, 13 Apr 2017 12:58:06 -0700 Subject: [PATCH] Remove native printing from test 980 and reliance on print internals In preparation for a making a CTS test out of this make the test not rely on internal allocation patterns of the 'System.out' object and not make use of std::cout. Test: ./test.py --host -j40 Change-Id: Ib7e874aaec71f93e834cf94ac5fe96663536691a --- test/980-redefine-object/check | 2 +- test/980-redefine-object/expected.txt | 56 +++++++--------------- test/980-redefine-object/redefine_object.cc | 58 ----------------------- test/980-redefine-object/src-ex/TestWatcher.java | 60 ++++++++++++++++++++++-- test/980-redefine-object/src/Main.java | 38 ++++++++++++--- test/Android.bp | 1 - 6 files changed, 105 insertions(+), 110 deletions(-) delete mode 100644 test/980-redefine-object/redefine_object.cc diff --git a/test/980-redefine-object/check b/test/980-redefine-object/check index 987066fe1..07b21b317 100755 --- a/test/980-redefine-object/check +++ b/test/980-redefine-object/check @@ -17,4 +17,4 @@ # The number of paused background threads (and therefore InterruptedExceptions) # can change so we will just delete their lines from the log. -sed "/Object allocated of type 'Ljava\/lang\/InterruptedException;'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null +sed "/Object allocated of type 'java\.lang\.InterruptedException'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null diff --git a/test/980-redefine-object/expected.txt b/test/980-redefine-object/expected.txt index 6e9bce027..4c294bc87 100644 --- a/test/980-redefine-object/expected.txt +++ b/test/980-redefine-object/expected.txt @@ -2,51 +2,31 @@ Allocating an j.l.Object before redefining Object class Allocating a Transform before redefining Object class Redefining the Object class to add a hook into the method -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' Allocating an j.l.Object after redefining Object class -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Object' Allocating a Transform after redefining Object class -Object allocated of type 'LTransform;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'Transform' Allocating an int[] after redefining Object class -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' Allocating an array list -Object allocated of type 'Ljava/util/ArrayList;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.util.ArrayList' Adding a bunch of stuff to the array list -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'LTransform;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.lang.Object' +Object allocated of type 'Transform' Allocating a linked list -Object allocated of type 'Ljava/util/LinkedList;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.util.LinkedList' Adding a bunch of stuff to the linked list -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/lang/Object;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'LTransform;' -Object allocated of type 'Ljava/util/LinkedList$Node;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'java.util.LinkedList$Node' +Object allocated of type 'Transform' +Object allocated of type 'java.util.LinkedList$Node' Throwing from down 4 stack frames -Object allocated of type 'Ljava/lang/Exception;' -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' +Object allocated of type 'java.lang.Exception' Exception caught. -Object allocated of type 'Ljava/lang/StringBuilder;' -Object allocated of type 'Ljava/nio/HeapCharBuffer;' Finishing test! diff --git a/test/980-redefine-object/redefine_object.cc b/test/980-redefine-object/redefine_object.cc deleted file mode 100644 index 1faf1a16a..000000000 --- a/test/980-redefine-object/redefine_object.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#include "android-base/stringprintf.h" -#include "base/logging.h" -#include "base/macros.h" -#include "jni.h" -#include "jvmti.h" -#include "scoped_utf_chars.h" - -// Test infrastructure -#include "jni_binder.h" -#include "jvmti_helper.h" -#include "test_env.h" - -namespace art { -namespace Test980RedefineObjects { - -extern "C" JNIEXPORT void JNICALL Java_Main_bindFunctionsForClass( - JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass target) { - BindFunctionsOnClass(jvmti_env, env, target); -} - -extern "C" JNIEXPORT void JNICALL Java_art_test_TestWatcher_NotifyConstructed( - JNIEnv* env, jclass TestWatcherClass ATTRIBUTE_UNUSED, jobject constructed) { - char* sig = nullptr; - char* generic_sig = nullptr; - if (JvmtiErrorToException(env, - jvmti_env, - jvmti_env->GetClassSignature(env->GetObjectClass(constructed), - &sig, - &generic_sig))) { - // Exception. - return; - } - std::cout << "Object allocated of type '" << sig << "'" << std::endl; - jvmti_env->Deallocate(reinterpret_cast(sig)); - jvmti_env->Deallocate(reinterpret_cast(generic_sig)); -} - -} // namespace Test980RedefineObjects -} // namespace art diff --git a/test/980-redefine-object/src-ex/TestWatcher.java b/test/980-redefine-object/src-ex/TestWatcher.java index d15e68871..c38e07bfe 100644 --- a/test/980-redefine-object/src-ex/TestWatcher.java +++ b/test/980-redefine-object/src-ex/TestWatcher.java @@ -16,10 +16,60 @@ package art.test; +import java.util.concurrent.locks.ReentrantLock; + public class TestWatcher { - // NB This function is native since it is called in the Object. method and so cannot cause - // any java allocations at all. The normal System.out.print* functions will cause allocations to - // occur so we cannot use them. This means the easiest way to report the object as being created - // is to go into native code and do it there. - public static native void NotifyConstructed(Object o); + // Lock to synchronize access to the static state of this class. + private static final ReentrantLock lock = new ReentrantLock(); + private static volatile boolean criticalFailure = false; + private static boolean reportingEnabled = true; + private static boolean doingReport = false; + + private static void MonitorEnter() { + lock.lock(); + } + + private static void MonitorExit() { + // Need to do this manually since we need to notify critical failure but would deadlock if + // waited for the unlock. + if (!lock.isHeldByCurrentThread()) { + NotifyCriticalFailure(); + throw new IllegalMonitorStateException("Locking error!"); + } else { + lock.unlock(); + } + } + + // Stops reporting. Must be paired with an EnableReporting call. + public static void DisableReporting() { + MonitorEnter(); + reportingEnabled = false; + } + + // Stops reporting. Must be paired with a DisableReporting call. + public static void EnableReporting() { + reportingEnabled = true; + MonitorExit(); + } + + public static void NotifyCriticalFailure() { + criticalFailure = true; + } + + public static void NotifyConstructed(Object o) { + if (criticalFailure) { + // Something went very wrong. We are probably trying to report it so don't get in the way. + return; + } + MonitorEnter(); + // We could enter an infinite loop if println allocates (which it does) so we disable + // reporting while we are doing a report. Since we are synchronized we won't miss any + // allocations. + if (reportingEnabled && !doingReport) { + doingReport = true; + System.out.println("Object allocated of type '" + o.getClass().getName() + "'"); + doingReport = false; + } + MonitorExit(); + } } diff --git a/test/980-redefine-object/src/Main.java b/test/980-redefine-object/src/Main.java index a50215e1a..7a82fde98 100644 --- a/test/980-redefine-object/src/Main.java +++ b/test/980-redefine-object/src/Main.java @@ -14,6 +14,7 @@ * limitations under the License. */ +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Base64; import java.util.LinkedList; @@ -287,6 +288,31 @@ public class Main { private static final String LISTENER_LOCATION = System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar"; + private static Method doEnableReporting; + private static Method doDisableReporting; + + private static void DisableReporting() { + if (doDisableReporting == null) { + return; + } + try { + doDisableReporting.invoke(null); + } catch (Exception e) { + throw new Error("Unable to disable reporting!"); + } + } + + private static void EnableReporting() { + if (doEnableReporting == null) { + return; + } + try { + doEnableReporting.invoke(null); + } catch (Exception e) { + throw new Error("Unable to enable reporting!"); + } + } + public static void main(String[] args) { art.Main.bindAgentJNIForClass(Main.class); doTest(); @@ -298,8 +324,8 @@ public class Main { addToBootClassLoader(LISTENER_LOCATION); // Load TestWatcher from the bootclassloader and make sure it is initialized. Class testwatcher_class = Class.forName("art.test.TestWatcher", true, null); - // Bind the native functions of testwatcher_class. - bindFunctionsForClass(testwatcher_class); + doEnableReporting = testwatcher_class.getDeclaredMethod("EnableReporting"); + doDisableReporting = testwatcher_class.getDeclaredMethod("DisableReporting"); } catch (Exception e) { throw new Error("Exception while making testwatcher", e); } @@ -308,9 +334,9 @@ public class Main { // NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and // "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called. private static void safePrintln(Object o) { - System.out.flush(); - System.out.print("\t" + o + "\n"); - System.out.flush(); + DisableReporting(); + System.out.println("\t" + o); + EnableReporting(); } private static void throwFrom(int depth) throws Exception { @@ -382,8 +408,6 @@ public class Main { private static native void addToBootClassLoader(String s); - private static native void bindFunctionsForClass(Class target); - // Transforms the class private static native void doCommonClassRedefinition(Class target, byte[] class_file, diff --git a/test/Android.bp b/test/Android.bp index 8059a2f20..538fac46c 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -297,7 +297,6 @@ art_cc_defaults { "936-search-onload/search_onload.cc", "944-transform-classloaders/classloader.cc", "945-obsolete-native/obsolete_native.cc", - "980-redefine-object/redefine_object.cc", "983-source-transform-verify/source_transform.cc", "984-obsolete-invoke/obsolete_invoke.cc", ], -- 2.11.0