Merge "ART: Add support for runtime debug checks" am: 7888b59b45
am: f37ac16f9e

Change-Id: Ie149b9bcb0043dfc6593cbbd5e27f86ccc9b3481
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 20f95c0..9b110eb 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -528,6 +528,7 @@
         "base/hash_set_test.cc",
         "base/hex_dump_test.cc",
         "base/histogram_test.cc",
+        "base/logging_test.cc",
         "base/mutex_test.cc",
         "base/safe_copy_test.cc",
         "base/scoped_flock_test.cc",
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index adfd7d3..2be9067 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -34,6 +34,55 @@
 
 namespace art {
 
+// We test here that the runtime-debug-checks are actually a no-op constexpr false in release
+// builds, as we can't check that in gtests (which are always debug).
+
+#ifdef NDEBUG
+namespace {
+DECLARE_RUNTIME_DEBUG_FLAG(kTestForConstexpr);
+static_assert(!kTestForConstexpr, "Issue with DECLARE_RUNTIME_DEBUG_FLAG in NDEBUG.");
+}
+#endif
+
+// Implementation of runtime debug flags. This should be compile-time optimized away in release
+// builds.
+namespace {
+bool gSlowEnabled = false;  // Default for slow flags is "off."
+
+// Use a function with a static to ensure our vector storage doesn't have initialization order
+// issues.
+std::vector<bool*>& GetFlagPtrs() {
+  static std::vector<bool*> g_flag_ptrs;
+  return g_flag_ptrs;
+}
+
+bool RegisterRuntimeDebugFlagImpl(bool* flag_ptr) {
+  GetFlagPtrs().push_back(flag_ptr);
+  return gSlowEnabled;
+}
+
+void SetRuntimeDebugFlagsEnabledImpl(bool enabled) {
+  gSlowEnabled = enabled;
+  for (bool* flag_ptr : GetFlagPtrs()) {
+    *flag_ptr = enabled;
+  }
+}
+
+}  // namespace
+
+bool RegisterRuntimeDebugFlag(bool* flag_ptr) {
+  if (kIsDebugBuild) {
+    return RegisterRuntimeDebugFlagImpl(flag_ptr);
+  }
+  return false;
+}
+
+void SetRuntimeDebugFlagsEnabled(bool enabled) {
+  if (kIsDebugBuild) {
+    SetRuntimeDebugFlagsEnabledImpl(enabled);
+  }
+}
+
 LogVerbosity gLogVerbosity;
 
 unsigned int gAborting = 0;
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index 7a9184e..d8954e5 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -62,6 +62,43 @@
 // Global log verbosity setting, initialized by InitLogging.
 extern LogVerbosity gLogVerbosity;
 
+// Runtime debug flags are flags that have a runtime component, that is, their value can be changed.
+// This is meant to implement fast vs slow debug builds, in that certain debug flags can be turned
+// on and off. To that effect, expose two macros to help implement and globally drive these flags:
+//
+// In the header, declare a (class) flag like this:
+//
+//   class C {
+//     DECLARE_RUNTIME_DEBUG_FLAG(kFlag);
+//   };
+//
+// This will declare a flag kFlag that is a constexpr false in release builds, and a static field
+// in debug builds. Usage is than uniform as C::kFlag.
+//
+// In the cc file, define the flag like this:
+//
+//   DEFINE_RUNTIME_DEBUG_FLAG(C, kFlag);
+//
+// This will define the static storage, as necessary, and register the flag with the runtime
+// infrastructure to toggle the value.
+
+#ifdef NDEBUG
+#define DECLARE_RUNTIME_DEBUG_FLAG(x) \
+  static constexpr bool x = false;
+// Note: the static_assert in the following only works for public flags. Fix this when we cross
+//       the line at some point.
+#define DEFINE_RUNTIME_DEBUG_FLAG(C, x) \
+  static_assert(!C::x, "Unexpected enabled flag in release build");
+#else
+#define DECLARE_RUNTIME_DEBUG_FLAG(x) \
+  static bool x;
+#define DEFINE_RUNTIME_DEBUG_FLAG(C, x) \
+  bool C::x = RegisterRuntimeDebugFlag(&C::x);
+#endif  // NDEBUG
+
+bool RegisterRuntimeDebugFlag(bool* runtime_debug_flag);
+void SetRuntimeDebugFlagsEnabled(bool enabled);
+
 // 0 if not abort, non-zero if an abort is in progress. Used on fatal exit to prevents recursive
 // aborts. Global declaration allows us to disable some error checking to ensure fatal shutdown
 // makes forward progress.
diff --git a/runtime/base/logging_test.cc b/runtime/base/logging_test.cc
new file mode 100644
index 0000000..d380b9e
--- /dev/null
+++ b/runtime/base/logging_test.cc
@@ -0,0 +1,59 @@
+/*
+ * 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 "logging.h"
+
+#include <type_traits>
+
+#include "android-base/logging.h"
+#include "base/bit_utils.h"
+#include "base/macros.h"
+#include "common_runtime_test.h"
+
+namespace art {
+
+static void SimpleAborter(const char* msg) {
+  LOG(FATAL_WITHOUT_ABORT) << msg;
+  _exit(1);
+}
+
+class LoggingTest : public CommonRuntimeTest {
+ protected:
+  void PostRuntimeCreate() OVERRIDE {
+    // In our abort tests we really don't want the runtime to create a real dump.
+    android::base::SetAborter(SimpleAborter);
+  }
+};
+
+#ifdef NDEBUG
+#error Unexpected NDEBUG
+#endif
+
+class TestClass {
+ public:
+  DECLARE_RUNTIME_DEBUG_FLAG(kFlag);
+};
+DEFINE_RUNTIME_DEBUG_FLAG(TestClass, kFlag);
+
+TEST_F(LoggingTest, DECL_DEF) {
+  SetRuntimeDebugFlagsEnabled(true);
+  EXPECT_TRUE(TestClass::kFlag);
+
+  SetRuntimeDebugFlagsEnabled(false);
+  EXPECT_FALSE(TestClass::kFlag);
+}
+
+}  // namespace art
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index f925994..5a4a26a 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -404,6 +404,7 @@
   options.push_back(std::make_pair("-Xcheck:jni", nullptr));
   options.push_back(std::make_pair(min_heap_string, nullptr));
   options.push_back(std::make_pair(max_heap_string, nullptr));
+  options.push_back(std::make_pair("-XX:SlowDebug=true", nullptr));
 
   callbacks_.reset(new NoopCompilerCallbacks());
 
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index abb6f8c..b1eb506 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -18,6 +18,7 @@
 
 #include <sstream>
 
+#include "base/logging.h"
 #include "base/stringpiece.h"
 #include "debugger.h"
 #include "gc/heap.h"
@@ -306,6 +307,10 @@
       .Define("-XX:ThreadSuspendTimeout=_")  // in ms
           .WithType<MillisecondsToNanoseconds>()  // store as ns
           .IntoKey(M::ThreadSuspendTimeout)
+      .Define("-XX:SlowDebug=_")
+          .WithType<bool>()
+          .WithValueMap({{"false", false}, {"true", true}})
+          .IntoKey(M::SlowDebug)
       .Ignore({
           "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
           "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
@@ -517,6 +522,8 @@
 
   MaybeOverrideVerbosity();
 
+  SetRuntimeDebugFlagsEnabled(args.Get(M::SlowDebug));
+
   // -Xprofile:
   Trace::SetDefaultClockSource(args.GetOrDefault(M::ProfileClock));
 
@@ -704,6 +711,7 @@
   UsageMessage(stream, "  -XX:LargeObjectSpace={disabled,map,freelist}\n");
   UsageMessage(stream, "  -XX:LargeObjectThreshold=N\n");
   UsageMessage(stream, "  -XX:DumpNativeStackOnSigQuit=booleanvalue\n");
+  UsageMessage(stream, "  -XX:SlowDebug={false,true}\n");
   UsageMessage(stream, "  -Xmethod-trace\n");
   UsageMessage(stream, "  -Xmethod-trace-file:filename");
   UsageMessage(stream, "  -Xmethod-trace-file-size:integervalue\n");
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index cfc681f..3d23e20 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -142,4 +142,6 @@
                                                                           // Runtime::Abort.
 RUNTIME_OPTIONS_KEY (void (*)(),          HookAbort,                      nullptr)
 
+RUNTIME_OPTIONS_KEY (bool,                SlowDebug,                      false)
+
 #undef RUNTIME_OPTIONS_KEY
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 5b93483..7a48bca 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -79,6 +79,9 @@
 # build step (e.g. dex2oat) were finished writing.
 SYNC_BEFORE_RUN="n"
 
+# When running a debug build, we want to run with all checks.
+ANDROID_FLAGS="${ANDROID_FLAGS} -XX:SlowDebug=true"
+
 while true; do
     if [ "x$1" = "x--quiet" ]; then
         QUIET="y"
diff --git a/tools/art b/tools/art
index 0bc08f0..2e5df91 100644
--- a/tools/art
+++ b/tools/art
@@ -24,6 +24,7 @@
 LIBART=libart.so
 JIT_PROFILE="no"
 VERBOSE="no"
+EXTRA_OPTIONS=""
 
 # Follow all sym links to get the program name.
 if [ z"$BASH_SOURCE" != z ]; then
@@ -147,6 +148,8 @@
     ;& # Fallthrough
   --debug)
     LIBART="libartd.so"
+    # Expect that debug mode wants all checks.
+    EXTRA_OPTIONS="${EXTRA_OPTIONS} -XX:SlowDebug=true"
     ;;
   --gdb)
     LIBART="libartd.so"
@@ -203,7 +206,6 @@
 
 LIBDIR="$(find_libdir $ART_BINARY_PATH)"
 LD_LIBRARY_PATH=$ANDROID_ROOT/$LIBDIR
-EXTRA_OPTIONS=""
 
 # If ANDROID_DATA is the system ANDROID_DATA or is not set, use our own,
 # and ensure we delete it at the end.
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index f742767..225fb39 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -154,7 +154,7 @@
 if [[ $debug == "yes" ]]; then
   art="$art -d"
   art_debugee="$art_debugee -d"
-  vm_args="$vm_args --vm-arg -XXlib:libartd.so"
+  vm_args="$vm_args --vm-arg -XXlib:libartd.so --vm-arg -XX:SlowDebug=true"
 fi
 if [[ $verbose == "yes" ]]; then
   # Enable JDWP logs in the debuggee.
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 8b3df3a..6dcc23a 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -127,7 +127,7 @@
   elif [[ "$1" == "--debug" ]]; then
     # Remove the --debug from the arguments.
     vogar_args=${vogar_args/$1}
-    vogar_args="$vogar_args --vm-arg -XXlib:libartd.so"
+    vogar_args="$vogar_args --vm-arg -XXlib:libartd.so --vm-arg -XX:SlowDebug=true"
     debug=true
     shift
   elif [[ "$1" == "-Xgc:gcstress" ]]; then