runtime: Add -Xverify:softfail and ART_TEST_INTERPRETER_ACCESS_CHECKS

Use ART_TEST_INTERPRETER_ACCESS_CHECKS=true to run all the tests through
the interpreter with access checks enabled. The normal interpreter tests
do not currently enable access checks, which means that a large part of
the interpreter codebase is untested.

The verifier will force every class into a soft fail mode if
-Xverify:softfail is used, thereby ensuring that if used along with the
interpreter (-Xint) that the interpret is always in access checks mode.

This is used alongside with --compile-filter=verify-at-runtime to
prevent the AOT compiler from putting down any code.

Change-Id: I35a10ed8c43d76fa96133cf01fdad497da387200
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 45b6490..2f43f5f 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -45,6 +45,7 @@
 
 # Do you want interpreter tests run?
 ART_TEST_INTERPRETER ?= $(ART_TEST_FULL)
+ART_TEST_INTERPRETER_ACCESS_CHECKS ?= $(ART_TEST_FULL)
 
 # Do you want JIT tests run?
 ART_TEST_JIT ?= $(ART_TEST_FULL)
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 728469c..c70e12d 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -31,7 +31,7 @@
 endif
 
 # Use dex2oat debug version for better error reporting
-# $(1): compiler - default, optimizing, jit or interpreter.
+# $(1): compiler - default, optimizing, jit, interpreter or interpreter-access-checks.
 # $(2): pic/no-pic
 # $(3): 2ND_ or undefined, 2ND_ for 32-bit host builds.
 # $(4): wrapper, e.g., valgrind.
@@ -64,12 +64,16 @@
     core_compile_options += --compiler-filter=interpret-only
     core_infix := -interpreter
   endif
+  ifeq ($(1),interpreter-access-checks)
+    core_compile_options += --compiler-filter=verify-at-runtime --runtime-arg -Xverify:softfail
+    core_infix := -interpreter-access-checks
+  endif
   ifeq ($(1),default)
     # Default has no infix, no compile options.
   endif
-  ifneq ($(filter-out default interpreter jit optimizing,$(1)),)
+  ifneq ($(filter-out default interpreter interpreter-access-checks jit optimizing,$(1)),)
     #Technically this test is not precise, but hopefully good enough.
-    $$(error found $(1) expected default, interpreter, jit or optimizing)
+    $$(error found $(1) expected default, interpreter, interpreter-access-checks, jit or optimizing)
   endif
 
   ifeq ($(2),pic)
@@ -127,7 +131,7 @@
   core_pic_infix :=
 endef  # create-core-oat-host-rules
 
-# $(1): compiler - default, optimizing, jit or interpreter.
+# $(1): compiler - default, optimizing, jit, interpreter or interpreter-access-checks.
 # $(2): wrapper.
 # $(3): dex2oat suffix.
 define create-core-oat-host-rule-combination
@@ -143,12 +147,14 @@
 $(eval $(call create-core-oat-host-rule-combination,default,,))
 $(eval $(call create-core-oat-host-rule-combination,optimizing,,))
 $(eval $(call create-core-oat-host-rule-combination,interpreter,,))
+$(eval $(call create-core-oat-host-rule-combination,interpreter-access-checks,,))
 
 valgrindHOST_CORE_IMG_OUTS :=
 valgrindHOST_CORE_OAT_OUTS :=
 $(eval $(call create-core-oat-host-rule-combination,default,valgrind,32))
 $(eval $(call create-core-oat-host-rule-combination,optimizing,valgrind,32))
 $(eval $(call create-core-oat-host-rule-combination,interpreter,valgrind,32))
+$(eval $(call create-core-oat-host-rule-combination,interpreter-access-checks,valgrind,32))
 
 valgrind-test-art-host-dex2oat-host: $(valgrindHOST_CORE_IMG_OUTS)
 
@@ -178,12 +184,16 @@
     core_compile_options += --compiler-filter=interpret-only
     core_infix := -interpreter
   endif
+  ifeq ($(1),interpreter-access-checks)
+    core_compile_options += --compiler-filter=verify-at-runtime --runtime-arg -Xverify:softfail
+    core_infix := -interpreter-access-checks
+  endif
   ifeq ($(1),default)
     # Default has no infix, no compile options.
   endif
-  ifneq ($(filter-out default interpreter jit optimizing,$(1)),)
+  ifneq ($(filter-out default interpreter interpreter-access-checks jit optimizing,$(1)),)
     # Technically this test is not precise, but hopefully good enough.
-    $$(error found $(1) expected default, interpreter, jit or optimizing)
+    $$(error found $(1) expected default, interpreter, interpreter-access-checks, jit or optimizing)
   endif
 
   ifeq ($(2),pic)
@@ -246,7 +256,7 @@
   core_pic_infix :=
 endef  # create-core-oat-target-rules
 
-# $(1): compiler - default, optimizing, jit or interpreter.
+# $(1): compiler - default, optimizing, jit, interpreter or interpreter-access-checks.
 # $(2): wrapper.
 # $(3): dex2oat suffix.
 define create-core-oat-target-rule-combination
@@ -262,12 +272,14 @@
 $(eval $(call create-core-oat-target-rule-combination,default,,))
 $(eval $(call create-core-oat-target-rule-combination,optimizing,,))
 $(eval $(call create-core-oat-target-rule-combination,interpreter,,))
+$(eval $(call create-core-oat-target-rule-combination,interpreter-access-checks,,))
 
 valgrindTARGET_CORE_IMG_OUTS :=
 valgrindTARGET_CORE_OAT_OUTS :=
 $(eval $(call create-core-oat-target-rule-combination,default,valgrind,32))
 $(eval $(call create-core-oat-target-rule-combination,optimizing,valgrind,32))
 $(eval $(call create-core-oat-target-rule-combination,interpreter,valgrind,32))
+$(eval $(call create-core-oat-target-rule-combination,interpreter-access-checks,valgrind,32))
 
 valgrind-test-art-host-dex2oat-target: $(valgrindTARGET_CORE_IMG_OUTS)
 
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 98fd327..52df7de 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -216,9 +216,6 @@
   EXPECT_SINGLE_PARSE_EXISTS("-Xzygote", M::Zygote);
   EXPECT_SINGLE_PARSE_VALUE_STR("/hello/world", "-Xbootclasspath:/hello/world", M::BootClassPath);
   EXPECT_SINGLE_PARSE_VALUE("/hello/world", "-Xbootclasspath:/hello/world", M::BootClassPath);
-  EXPECT_SINGLE_PARSE_VALUE(false, "-Xverify:none", M::Verify);
-  EXPECT_SINGLE_PARSE_VALUE(true, "-Xverify:remote", M::Verify);
-  EXPECT_SINGLE_PARSE_VALUE(true, "-Xverify:all", M::Verify);
   EXPECT_SINGLE_PARSE_VALUE(Memory<1>(234), "-Xss234", M::StackSize);
   EXPECT_SINGLE_PARSE_VALUE(MemoryKiB(1234*MB), "-Xms1234m", M::MemoryInitialSize);
   EXPECT_SINGLE_PARSE_VALUE(true, "-XX:EnableHSpaceCompactForOOM", M::EnableHSpaceCompactForOOM);
@@ -550,6 +547,14 @@
                             M::ExperimentalLambdas);
 }
 
+// -Xverify:_
+TEST_F(CmdlineParserTest, TestVerify) {
+  EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kNone,     "-Xverify:none",     M::Verify);
+  EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kEnable,   "-Xverify:remote",   M::Verify);
+  EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kEnable,   "-Xverify:all",      M::Verify);
+  EXPECT_SINGLE_PARSE_VALUE(verifier::VerifyMode::kSoftFail, "-Xverify:softfail", M::Verify);
+}
+
 TEST_F(CmdlineParserTest, TestIgnoreUnrecognized) {
   RuntimeParser::Builder parserBuilder;
 
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index e0d7708..9325454 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1950,9 +1950,12 @@
       }
       state->stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
 
+      uint32_t method_access_flags = method->GetAccessFlags();
+
       indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
-      indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
-                                dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
+      indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd AccessFlags=0x%x\n",
+                                dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes,
+                                method_access_flags);
 
       size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
           vmap_table_bytes + quick_oat_code_size + ArtMethod::ObjectSize(image_pointer_size);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5798c04..8f7862a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3040,6 +3040,18 @@
     mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifyingAtRuntime, self);
   }
 
+  // Skip verification if we are forcing a soft fail.
+  // This has to be before the normal verification enabled check,
+  // since technically verification is disabled in this mode.
+  if (UNLIKELY(Runtime::Current()->IsVerificationSoftFail())) {
+    // Force verification to be a 'soft failure'.
+    mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
+    // As this is a fake verified status, make sure the methods are _not_ marked preverified
+    // later.
+    klass->SetPreverified();
+    return;
+  }
+
   // Skip verification if disabled.
   if (!Runtime::Current()->IsVerificationEnabled()) {
     mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index d08af71..7772354 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -244,10 +244,11 @@
           .AppendValues()
           .IntoKey(M::ImageCompilerOptions)
       .Define("-Xverify:_")
-          .WithType<bool>()
-          .WithValueMap({{"none", false},
-                         {"remote", true},
-                         {"all", true}})
+          .WithType<verifier::VerifyMode>()
+          .WithValueMap({{"none",     verifier::VerifyMode::kNone},
+                         {"remote",   verifier::VerifyMode::kEnable},
+                         {"all",      verifier::VerifyMode::kEnable},
+                         {"softfail", verifier::VerifyMode::kSoftFail}})
           .IntoKey(M::Verify)
       .Define("-XX:NativeBridge=_")
           .WithType<std::string>()
@@ -686,7 +687,7 @@
   UsageMessage(stream, "  -esa\n");
   UsageMessage(stream, "  -dsa\n");
   UsageMessage(stream, "   (-enablesystemassertions, -disablesystemassertions)\n");
-  UsageMessage(stream, "  -Xverify:{none,remote,all}\n");
+  UsageMessage(stream, "  -Xverify:{none,remote,all,softfail}\n");
   UsageMessage(stream, "  -Xrs\n");
   UsageMessage(stream, "  -Xint:portable, -Xint:fast, -Xint:jit\n");
   UsageMessage(stream, "  -Xdexopt:{none,verified,all,full}\n");
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 3b0ca9e..c5aece5 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -185,7 +185,7 @@
       system_class_loader_(nullptr),
       dump_gc_performance_on_shutdown_(false),
       preinitialization_transaction_(nullptr),
-      verify_(false),
+      verify_(verifier::VerifyMode::kNone),
       allow_dex_file_fallback_(true),
       target_sdk_version_(0),
       implicit_null_checks_(false),
@@ -1757,4 +1757,12 @@
   imt_unimplemented_method_ = method;
 }
 
+bool Runtime::IsVerificationEnabled() const {
+  return verify_ == verifier::VerifyMode::kEnable;
+}
+
+bool Runtime::IsVerificationSoftFail() const {
+  return verify_ == verifier::VerifyMode::kSoftFail;
+}
+
 }  // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 9ee96a3..806292f 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -64,6 +64,7 @@
 }  // namespace mirror
 namespace verifier {
   class MethodVerifier;
+  enum class VerifyMode : int8_t;
 }  // namespace verifier
 class ArenaPool;
 class ArtMethod;
@@ -500,9 +501,8 @@
     return !implicit_so_checks_;
   }
 
-  bool IsVerificationEnabled() const {
-    return verify_;
-  }
+  bool IsVerificationEnabled() const;
+  bool IsVerificationSoftFail() const;
 
   bool IsDexFileFallbackEnabled() const {
     return allow_dex_file_fallback_;
@@ -700,8 +700,8 @@
   // Transaction used for pre-initializing classes at compilation time.
   Transaction* preinitialization_transaction_;
 
-  // If false, verification is disabled. True by default.
-  bool verify_;
+  // If kNone, verification is disabled. kEnable by default.
+  verifier::VerifyMode verify_;
 
   // If true, the runtime may use dex files directly with the interpreter if an oat file is not
   // available/usable.
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index dc4c0c7..9922c5f 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -106,7 +106,8 @@
                                           CompilerOptions)  // -Xcompiler-option ...
 RUNTIME_OPTIONS_KEY (std::vector<std::string>, \
                                           ImageCompilerOptions)  // -Ximage-compiler-option ...
-RUNTIME_OPTIONS_KEY (bool,                Verify,                         true)
+RUNTIME_OPTIONS_KEY (verifier::VerifyMode, \
+                                          Verify,                         verifier::VerifyMode::kEnable)
 RUNTIME_OPTIONS_KEY (std::string,         NativeBridge)
 RUNTIME_OPTIONS_KEY (unsigned int,        ZygoteMaxFailedBoots,           10)
 RUNTIME_OPTIONS_KEY (Unit,                NoDexFileFallback)
diff --git a/runtime/runtime_options.h b/runtime/runtime_options.h
index 7e59000..88ac00a 100644
--- a/runtime/runtime_options.h
+++ b/runtime/runtime_options.h
@@ -32,6 +32,7 @@
 #include "gc/space/large_object_space.h"
 #include "profiler_options.h"
 #include "arch/instruction_set.h"
+#include "verifier/verify_mode.h"
 #include <stdio.h>
 #include <stdarg.h>
 
diff --git a/runtime/verifier/verify_mode.h b/runtime/verifier/verify_mode.h
new file mode 100644
index 0000000..bea4378
--- /dev/null
+++ b/runtime/verifier/verify_mode.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_VERIFIER_VERIFY_MODE_H_
+#define ART_RUNTIME_VERIFIER_VERIFY_MODE_H_
+
+#include <stdint.h>
+
+namespace art {
+namespace verifier {
+
+// The mode that the verifier should run as.
+enum class VerifyMode : int8_t {
+  kNone,      // Everything is assumed verified.
+  kEnable,    // Standard verification, try pre-verifying at compile-time.
+  kSoftFail,  // Force a soft fail, punting to the interpreter with access checks.
+};
+
+}  // namespace verifier
+}  // namespace art
+
+#endif  // ART_RUNTIME_VERIFIER_VERIFY_MODE_H_
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 65ddf8d..3d5c483 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -112,6 +112,9 @@
 ifeq ($(ART_TEST_DEFAULT_COMPILER),true)
   COMPILER_TYPES += default
 endif
+ifeq ($(ART_TEST_INTERPRETER_ACCESS_CHECKS),true)
+  COMPILER_TYPES += interpreter-access-checks
+endif
 ifeq ($(ART_TEST_INTERPRETER),true)
   COMPILER_TYPES += interpreter
 endif
@@ -260,6 +263,28 @@
 
 TEST_ART_BROKEN_NO_RELOCATE_TESTS :=
 
+# Temporarily disable some broken tests when forcing access checks in interpreter b/22414682
+TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS := \
+  004-JniTest \
+  005-annotations \
+  044-proxy \
+  073-mismatched-field \
+  088-monitor-verification \
+  135-MirandaDispatch \
+  137-cfi \
+  412-new-array \
+  471-uninitialized-locals \
+  506-verify-aput \
+  800-smali
+
+ifneq (,$(filter interpreter-access-checks,$(COMPILER_TYPES)))
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+      interpreter-access-checks,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+      $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS), $(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS :=
+
 # Tests that are broken with GC stress.
 # 137-cfi needs to unwind a second forked process. We're using a primitive sleep to wait till we
 # hope the second process got into the expected state. The slowness of gcstress makes this bad.
@@ -604,7 +629,8 @@
 
 # Create a rule to build and run a tests following the form:
 # test-art-{1: host or target}-run-test-{2: debug ndebug}-{3: prebuild no-prebuild no-dex2oat}-
-#    {4: interpreter default optimizing jit}-{5: relocate nrelocate relocate-npatchoat}-
+#    {4: interpreter default optimizing jit interpreter-access-checks}-
+#    {5: relocate nrelocate relocate-npatchoat}-
 #    {6: trace or ntrace}-{7: gcstress gcverify cms}-{8: forcecopy checkjni jni}-
 #    {9: no-image image picimage}-{10: pictest npictest}-
 #    {11: ndebuggable debuggable}-{12: test name}{13: 32 or 64}
@@ -674,6 +700,9 @@
     ifeq ($(4),interpreter)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_INTERPRETER_RULES
       run_test_options += --interpreter
+    else ifeq ($(4),interpreter-access-checks)
+      test_groups += ART_RUN_TEST_$$(uc_host_or_target)_INTERPRETER_ACCESS_CHECKS_RULES
+      run_test_options += --interpreter --verify-soft-fail
     else
       ifeq ($(4),default)
         test_groups += ART_RUN_TEST_$$(uc_host_or_target)_DEFAULT_RULES
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 842d87e..db64b77 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -42,7 +42,7 @@
 TIME_OUT_VALUE=10
 USE_GDB="n"
 USE_JVM="n"
-VERIFY="y"
+VERIFY="y" # y=yes,n=no,s=softfail
 ZYGOTE=""
 DEX_VERIFY=""
 USE_DEX2OAT_AND_PATCHOAT="y"
@@ -149,6 +149,9 @@
     elif [ "x$1" = "x--no-verify" ]; then
         VERIFY="n"
         shift
+    elif [ "x$1" = "x--verify-soft-fail" ]; then
+        VERIFY="s"
+        shift
     elif [ "x$1" = "x--no-optimize" ]; then
         OPTIMIZE="n"
         shift
@@ -201,7 +204,11 @@
     if [ "$VERIFY" = "y" ]; then
         JVM_VERIFY_ARG="-Xverify:all"
         msg "Performing verification"
-    else
+    elif [ "$VERIFY" = "s" ]; then
+        JVM_VERIFY_ARG="Xverify:all"
+        DEX_VERIFY="-Xverify:softfail"
+        msg "Forcing verification to be soft fail"
+    else # VERIFY = "n"
         DEX_VERIFY="-Xverify:none"
         JVM_VERIFY_ARG="-Xverify:none"
         msg "Skipping verification"
@@ -263,7 +270,10 @@
     INT_OPTS="-Xint"
     if [ "$VERIFY" = "y" ] ; then
       COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
-    else
+    elif [ "$VERIFY" = "s" ]; then
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-at-runtime"
+      DEX_VERIFY="${DEX_VERIFY} -Xverify:softfail"
+    else # VERIFY = "n"
       COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none"
       DEX_VERIFY="${DEX_VERIFY} -Xverify:none"
     fi
diff --git a/test/run-test b/test/run-test
index bdf680b..eabbab3 100755
--- a/test/run-test
+++ b/test/run-test
@@ -262,6 +262,10 @@
     elif [ "x$1" = "x--no-verify" ]; then
         run_args="${run_args} --no-verify"
         shift
+    elif [ "x$1" = "x--verify-soft-fail" ]; then
+        run_args="${run_args} --verify-soft-fail"
+        image_suffix="-interpreter-access-checks"
+        shift
     elif [ "x$1" = "x--no-optimize" ]; then
         run_args="${run_args} --no-optimize"
         shift
@@ -520,6 +524,9 @@
         echo "    --optimizing          Enable optimizing compiler (default)."
         echo "    --quick               Use Quick compiler (off by default)."
         echo "    --no-verify           Turn off verification (on by default)."
+        echo "    --verify-soft-fail    Force soft fail verification (off by default)."
+        echo "                          Verification is enabled if neither --no-verify"
+        echo "                          nor --verify-soft-fail is specified."
         echo "    --no-optimize         Turn off optimization (on by default)."
         echo "    --no-precise          Turn off precise GC (on by default)."
         echo "    --zygote              Spawn the process from the Zygote." \