Merge "Revert "Remove support for Valgrind in ART.""
diff --git a/Android.mk b/Android.mk
index 1c94629..08a1a10 100644
--- a/Android.mk
+++ b/Android.mk
@@ -245,6 +245,19 @@
 test-art-host-dexdump: $(addprefix $(HOST_OUT_EXECUTABLES)/, dexdump2 dexlist)
 	ANDROID_HOST_OUT=$(realpath $(HOST_OUT)) art/test/dexdump/run-all-tests
 
+# Valgrind.
+.PHONY: valgrind-test-art-host
+valgrind-test-art-host: valgrind-test-art-host-gtest
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: valgrind-test-art-host32
+valgrind-test-art-host32: valgrind-test-art-host-gtest32
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: valgrind-test-art-host64
+valgrind-test-art-host64: valgrind-test-art-host-gtest64
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
 ########################################################################
 # target test rules
 
@@ -319,6 +332,19 @@
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 endif
 
+# Valgrind.
+.PHONY: valgrind-test-art-target
+valgrind-test-art-target: valgrind-test-art-target-gtest
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: valgrind-test-art-target32
+valgrind-test-art-target32: valgrind-test-art-target-gtest32
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: valgrind-test-art-target64
+valgrind-test-art-target64: valgrind-test-art-target-gtest64
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
 
 #######################
 # Fake packages for ART
diff --git a/build/Android.bp b/build/Android.bp
index 3a1d583..2a5598f 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -127,6 +127,8 @@
     },
 
     include_dirs: [
+        "external/valgrind/include",
+        "external/valgrind",
         "external/vixl/src",
     ],
 
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index c3f81a6..b481352 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -408,9 +408,15 @@
 ART_TEST_HOST_GTEST$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
 ART_TEST_HOST_GTEST$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
 ART_TEST_HOST_GTEST_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST_RULES :=
 ART_TEST_TARGET_GTEST$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST_RULES :=
+ART_TEST_TARGET_VALGRIND_GTEST$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_VALGRIND_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_VALGRIND_GTEST_RULES :=
 ART_TEST_HOST_GTEST_DEPENDENCIES :=
 
 ART_GTEST_TARGET_ANDROID_ROOT := '/system'
@@ -418,6 +424,40 @@
   ART_GTEST_TARGET_ANDROID_ROOT := $(ART_TEST_ANDROID_ROOT)
 endif
 
+ART_VALGRIND_TARGET_DEPENDENCIES :=
+
+# Has to match list in external/valgrind/Android.build_one.mk
+ART_VALGRIND_SUPPORTED_ARCH := arm arm64 x86_64
+
+# Valgrind is not supported for x86
+ifneq (,$(filter $(ART_VALGRIND_SUPPORTED_ARCH),$(TARGET_ARCH)))
+art_vg_arch := $(if $(filter x86_64,$(TARGET_ARCH)),amd64,$(TARGET_ARCH))
+ART_VALGRIND_TARGET_DEPENDENCIES += \
+  $(TARGET_OUT_EXECUTABLES)/valgrind \
+  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/memcheck-$(art_vg_arch)-linux \
+  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_core-$(art_vg_arch)-linux.so \
+  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_memcheck-$(art_vg_arch)-linux.so \
+  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/default.supp
+art_vg_arch :=
+endif
+
+ifdef TARGET_2ND_ARCH
+ifneq (,$(filter $(ART_VALGRIND_SUPPORTED_ARCH),$(TARGET_2ND_ARCH)))
+ART_VALGRIND_TARGET_DEPENDENCIES += \
+  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/memcheck-$(TARGET_2ND_ARCH)-linux \
+  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_core-$(TARGET_2ND_ARCH)-linux.so \
+  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_memcheck-$(TARGET_2ND_ARCH)-linux.so
+endif
+endif
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := valgrind-target-suppressions.txt
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := test/valgrind-target-suppressions.txt
+LOCAL_MODULE_PATH := $(ART_TARGET_TEST_OUT)
+include $(BUILD_PREBUILT)
+
 # Define a make rule for a target device gtest.
 # $(1): gtest name - the name of the test we're building such as leb128_test.
 # $(2): path relative to $OUT to the test binary
@@ -437,9 +477,10 @@
     $$($(3)TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so \
     $$($(3)TARGET_OUT_SHARED_LIBRARIES)/libopenjdkd.so \
     $$(TARGET_OUT_JAVA_LIBRARIES)/core-libart-testdex.jar \
-    $$(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar
+    $$(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar \
+    $$(ART_TARGET_TEST_OUT)/valgrind-target-suppressions.txt
 
-$$(gtest_rule): PRIVATE_TARGET_EXE := $$(gtest_target_exe)
+$$(gtest_rule) valgrind-$$(gtest_rule): PRIVATE_TARGET_EXE := $$(gtest_target_exe)
 
 ifeq ($(ART_TEST_CHROOT),)
 # Non-chroot configuration.
@@ -474,7 +515,37 @@
   ART_TEST_TARGET_GTEST_RULES += $$(gtest_rule)
   ART_TEST_TARGET_GTEST_$(1)_RULES += $$(gtest_rule)
 
+# File witnessing the success of the Valgrind gtest, the presence of which means the gtest's
+# success.
+valgrind_gtest_witness := \
+  $(maybe_art_test_chroot)$(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/valgrind-$$(gtest_rule)-$$$$PPID
+
+valgrind-$$(gtest_rule): VALGRIND_GTEST_WITNESS := $$(valgrind_gtest_witness)
+
+.PHONY: valgrind-$$(gtest_rule)
+valgrind-$$(gtest_rule): $(ART_VALGRIND_TARGET_DEPENDENCIES) test-art-target-sync
+	$(hide) adb shell touch $$(VALGRIND_GTEST_WITNESS)
+	$(hide) adb shell rm $$(VALGRIND_GTEST_WITNESS)
+	$(hide) adb shell chmod 755 $(maybe_art_test_chroot)$$(PRIVATE_TARGET_EXE)
+	$(hide) $$(call ART_TEST_SKIP,$$@) && \
+	  (adb shell "$(maybe_chroot_command) env $(GCOV_ENV) LD_LIBRARY_PATH=$(4) \
+	       ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
+	       $(ART_GTEST_TARGET_ANDROID_ROOT)/bin/valgrind \
+	       --leak-check=full --error-exitcode=1 --workaround-gcc296-bugs=yes \
+	       --suppressions=$(ART_TARGET_TEST_DIR)/valgrind-target-suppressions.txt \
+	       --num-callers=50 --show-mismatched-frees=no $$(PRIVATE_TARGET_EXE) \
+	     && touch $$(VALGRIND_GTEST_WITNESS)" \
+	   && (adb pull $$(VALGRIND_GTEST_WITNESS) /tmp/ && $$(call ART_TEST_PASSED,$$@)) \
+	   || $$(call ART_TEST_FAILED,$$@))
+	$(hide) rm -f /tmp/$$@-$$$$PPID
+
+  ART_TEST_TARGET_VALGRIND_GTEST$$($(3)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += \
+    valgrind-$$(gtest_rule)
+  ART_TEST_TARGET_VALGRIND_GTEST_RULES += valgrind-$$(gtest_rule)
+  ART_TEST_TARGET_VALGRIND_GTEST_$(1)_RULES += valgrind-$$(gtest_rule)
+
   # Clear locally defined variables.
+  valgrind_gtest_witness :=
   gtest_witness :=
   maybe_chroot_command :=
   maybe_art_test_chroot :=
@@ -483,6 +554,16 @@
   gtest_rule :=
 endef  # define-art-gtest-rule-target
 
+ART_VALGRIND_DEPENDENCIES := \
+  $(HOST_OUT_EXECUTABLES)/valgrind \
+  $(HOST_OUT)/lib64/valgrind/memcheck-amd64-linux \
+  $(HOST_OUT)/lib64/valgrind/memcheck-x86-linux \
+  $(HOST_OUT)/lib64/valgrind/default.supp \
+  $(HOST_OUT)/lib64/valgrind/vgpreload_core-amd64-linux.so \
+  $(HOST_OUT)/lib64/valgrind/vgpreload_core-x86-linux.so \
+  $(HOST_OUT)/lib64/valgrind/vgpreload_memcheck-amd64-linux.so \
+  $(HOST_OUT)/lib64/valgrind/vgpreload_memcheck-x86-linux.so
+
 # Define make rules for a host gtests.
 # $(1): gtest name - the name of the test we're building such as leb128_test.
 # $(2): path relative to $OUT to the test binary
@@ -534,6 +615,19 @@
   ART_TEST_HOST_GTEST_$(1)_RULES += $$(gtest_rule)
 
 
+.PHONY: valgrind-$$(gtest_rule)
+valgrind-$$(gtest_rule): $$(gtest_exe) $$(gtest_deps) $(ART_VALGRIND_DEPENDENCIES)
+	$(hide) $$(call ART_TEST_SKIP,$$@) && \
+	  VALGRIND_LIB=$(HOST_OUT)/lib64/valgrind \
+	  $(HOST_OUT_EXECUTABLES)/valgrind --leak-check=full --error-exitcode=1 \
+	    --suppressions=art/test/valgrind-suppressions.txt --num-callers=50 \
+	    $$< && \
+	    $$(call ART_TEST_PASSED,$$@) || $$(call ART_TEST_FAILED,$$@)
+
+  ART_TEST_HOST_VALGRIND_GTEST$$($(3)ART_PHONY_TEST_HOST_SUFFIX)_RULES += valgrind-$$(gtest_rule)
+  ART_TEST_HOST_VALGRIND_GTEST_RULES += valgrind-$$(gtest_rule)
+  ART_TEST_HOST_VALGRIND_GTEST_$(1)_RULES += valgrind-$$(gtest_rule)
+
   # Clear locally defined variables.
   gtest_deps :=
   gtest_exe :=
@@ -566,6 +660,7 @@
 
   ifndef ART_TEST_TARGET_GTEST_$$(art_gtest_name)_RULES
     ART_TEST_TARGET_GTEST_$$(art_gtest_name)_RULES :=
+    ART_TEST_TARGET_VALGRIND_GTEST_$$(art_gtest_name)_RULES :=
   endif
   $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),$$(art_gtest_filename),$(2),$$($(2)library_path)))
 
@@ -585,6 +680,7 @@
   art_gtest_name := $$(notdir $$(basename $$(art_gtest_filename)))
   ifndef ART_TEST_HOST_GTEST_$$(art_gtest_name)_RULES
     ART_TEST_HOST_GTEST_$$(art_gtest_name)_RULES :=
+    ART_TEST_HOST_VALGRIND_GTEST_$$(art_gtest_name)_RULES :=
   endif
   $$(eval $$(call define-art-gtest-rule-host,$$(art_gtest_name),$$(art_gtest_filename),$(2)))
 
@@ -603,8 +699,13 @@
 test-art-target-gtest-$$(art_gtest_name): $$(ART_TEST_TARGET_GTEST_$$(art_gtest_name)_RULES)
 	$$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
 
+.PHONY: valgrind-test-art-target-gtest-$$(art_gtest_name)
+valgrind-test-art-target-gtest-$$(art_gtest_name): $$(ART_TEST_TARGET_VALGRIND_GTEST_$$(art_gtest_name)_RULES)
+	$$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
+
   # Clear now unused variables.
   ART_TEST_TARGET_GTEST_$$(art_gtest_name)_RULES :=
+  ART_TEST_TARGET_VALGRIND_GTEST_$$(art_gtest_name)_RULES :=
   art_gtest_name :=
 endef  # define-art-gtest-target-both
 
@@ -617,8 +718,13 @@
 test-art-host-gtest-$$(art_gtest_name): $$(ART_TEST_HOST_GTEST_$$(art_gtest_name)_RULES)
 	$$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
 
+.PHONY: valgrind-test-art-host-gtest-$$(art_gtest_name)
+valgrind-test-art-host-gtest-$$(art_gtest_name): $$(ART_TEST_HOST_VALGRIND_GTEST_$$(art_gtest_name)_RULES)
+	$$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
+
   # Clear now unused variables.
   ART_TEST_HOST_GTEST_$$(art_gtest_name)_RULES :=
+  ART_TEST_HOST_VALGRIND_GTEST_$$(art_gtest_name)_RULES :=
   art_gtest_name :=
 endef  # define-art-gtest-host-both
 
@@ -644,11 +750,12 @@
 $(foreach file, $(ART_TARGET_GTEST_FILES), $(eval RUNTIME_TARGET_GTEST_MAKE_TARGETS += $$(notdir $$(patsubst %/,%,$$(dir $$(file))))_$$(notdir $$(basename $$(file)))))
 COMPILER_TARGET_GTEST_MAKE_TARGETS :=
 
-# Define all the combinations of host/target and suffix such as:
-# test-art-host-gtest or test-art-host-gtest64
+# Define all the combinations of host/target, valgrind and suffix such as:
+# test-art-host-gtest or valgrind-test-art-host-gtest64
 # $(1): host or target
 # $(2): HOST or TARGET
-# $(3): undefined, 32 or 64
+# $(3): valgrind- or undefined
+# $(4): undefined, 32 or 64
 define define-test-art-gtest-combination
   ifeq ($(1),host)
     ifneq ($(2),HOST)
@@ -663,8 +770,12 @@
     endif
   endif
 
-  rule_name := test-art-$(1)-gtest$(3)
-  dependencies := $$(ART_TEST_$(2)_GTEST$(3)_RULES)
+  rule_name := $(3)test-art-$(1)-gtest$(4)
+  ifeq ($(3),valgrind-)
+    dependencies := $$(ART_TEST_$(2)_VALGRIND_GTEST$(4)_RULES)
+  else
+    dependencies := $$(ART_TEST_$(2)_GTEST$(4)_RULES)
+  endif
 
 .PHONY: $$(rule_name)
 $$(rule_name): $$(dependencies) dx d8-compat-dx desugar
@@ -675,15 +786,21 @@
   dependencies :=
 endef  # define-test-art-gtest-combination
 
-$(eval $(call define-test-art-gtest-combination,target,TARGET,))
-$(eval $(call define-test-art-gtest-combination,target,TARGET,$(ART_PHONY_TEST_TARGET_SUFFIX)))
+$(eval $(call define-test-art-gtest-combination,target,TARGET,,))
+$(eval $(call define-test-art-gtest-combination,target,TARGET,valgrind-,))
+$(eval $(call define-test-art-gtest-combination,target,TARGET,,$(ART_PHONY_TEST_TARGET_SUFFIX)))
+$(eval $(call define-test-art-gtest-combination,target,TARGET,valgrind-,$(ART_PHONY_TEST_TARGET_SUFFIX)))
 ifdef 2ND_ART_PHONY_TEST_TARGET_SUFFIX
-$(eval $(call define-test-art-gtest-combination,target,TARGET,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
+$(eval $(call define-test-art-gtest-combination,target,TARGET,,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
+$(eval $(call define-test-art-gtest-combination,target,TARGET,valgrind-,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
 endif
-$(eval $(call define-test-art-gtest-combination,host,HOST,))
-$(eval $(call define-test-art-gtest-combination,host,HOST,$(ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-gtest-combination,host,HOST,,))
+$(eval $(call define-test-art-gtest-combination,host,HOST,valgrind-,))
+$(eval $(call define-test-art-gtest-combination,host,HOST,,$(ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-gtest-combination,host,HOST,valgrind-,$(ART_PHONY_TEST_HOST_SUFFIX)))
 ifneq ($(HOST_PREFER_32_BIT),true)
-$(eval $(call define-test-art-gtest-combination,host,HOST,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-gtest-combination,host,HOST,,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-gtest-combination,host,HOST,valgrind-,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
 endif
 
 # Clear locally defined variables.
@@ -700,9 +817,15 @@
 ART_TEST_HOST_GTEST$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
 ART_TEST_HOST_GTEST$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
 ART_TEST_HOST_GTEST_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST_RULES :=
 ART_TEST_TARGET_GTEST$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST_RULES :=
+ART_TEST_TARGET_VALGRIND_GTEST$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_VALGRIND_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_VALGRIND_GTEST_RULES :=
 ART_GTEST_TARGET_ANDROID_ROOT :=
 ART_GTEST_class_linker_test_DEX_DEPS :=
 ART_GTEST_class_table_test_DEX_DEPS :=
@@ -741,6 +864,8 @@
 ART_GTEST_dex2oat_environment_tests_DEX_DEPS :=
 ART_GTEST_heap_verification_test_DEX_DEPS :=
 ART_GTEST_verifier_deps_test_DEX_DEPS :=
+ART_VALGRIND_DEPENDENCIES :=
+ART_VALGRIND_TARGET_DEPENDENCIES :=
 $(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval ART_TEST_TARGET_GTEST_$(dir)_DEX :=))
 $(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval ART_TEST_HOST_GTEST_$(dir)_DEX :=))
 ART_TEST_HOST_GTEST_MainStripped_DEX :=
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index ba3ef05..517ac5c 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -37,9 +37,11 @@
 endif
 
 # Use dex2oat debug version for better error reporting
-# $(1): compiler - optimizing, interpreter or interp-ac (interpreter-access-checks).
+# $(1): compiler - optimizing, interpreter or interpreter-access-checks.
 # $(2): 2ND_ or undefined, 2ND_ for 32-bit host builds.
-# $(3): multi-image.
+# $(3): wrapper, e.g., valgrind.
+# $(4): dex2oat suffix, e.g, valgrind requires 32 right now.
+# $(5): multi-image.
 # NB depending on HOST_CORE_DEX_LOCATIONS so we are sure to have the dex files in frameworks for
 # run-test --no-image
 define create-core-oat-host-rules
@@ -63,11 +65,11 @@
   endif
   ifneq ($(filter-out interpreter interp-ac optimizing,$(1)),)
     #Technically this test is not precise, but hopefully good enough.
-    $$(error found $(1) expected interpreter, interp-ac, or optimizing)
+    $$(error found $(1) expected interpreter, interpreter-access-checks, or optimizing)
   endif
 
-  # If $(3) is true, generate a multi-image.
-  ifeq ($(3),true)
+  # If $(5) is true, generate a multi-image.
+  ifeq ($(5),true)
     core_multi_infix := -multi
     core_multi_param := --multi-image --no-inline-from=core-oj-hostdex.jar
     core_multi_group := _multi
@@ -77,18 +79,22 @@
     core_multi_group :=
   endif
 
-  core_image_name := $($(2)HOST_CORE_IMG_OUT_BASE)$$(core_infix)$$(core_multi_infix)$(CORE_IMG_SUFFIX)
-  core_oat_name := $($(2)HOST_CORE_OAT_OUT_BASE)$$(core_infix)$$(core_multi_infix)$(CORE_OAT_SUFFIX)
+  core_image_name := $($(2)HOST_CORE_IMG_OUT_BASE)$$(core_infix)$$(core_multi_infix)$(3)$(CORE_IMG_SUFFIX)
+  core_oat_name := $($(2)HOST_CORE_OAT_OUT_BASE)$$(core_infix)$$(core_multi_infix)$(3)$(CORE_OAT_SUFFIX)
 
   # Using the bitness suffix makes it easier to add as a dependency for the run-test mk.
   ifeq ($(2),)
-    HOST_CORE_IMAGE_$(1)$$(core_multi_group)_64 := $$(core_image_name)
+    $(3)HOST_CORE_IMAGE_$(1)$$(core_multi_group)_64 := $$(core_image_name)
   else
-    HOST_CORE_IMAGE_$(1)$$(core_multi_group)_32 := $$(core_image_name)
+    $(3)HOST_CORE_IMAGE_$(1)$$(core_multi_group)_32 := $$(core_image_name)
   endif
-  HOST_CORE_IMG_OUTS += $$(core_image_name)
-  HOST_CORE_OAT_OUTS += $$(core_oat_name)
+  $(3)HOST_CORE_IMG_OUTS += $$(core_image_name)
+  $(3)HOST_CORE_OAT_OUTS += $$(core_oat_name)
 
+  # If we have a wrapper, make the target phony.
+  ifneq ($(3),)
+.PHONY: $$(core_image_name)
+  endif
 $$(core_image_name): PRIVATE_CORE_COMPILE_OPTIONS := $$(core_compile_options)
 $$(core_image_name): PRIVATE_CORE_IMG_NAME := $$(core_image_name)
 $$(core_image_name): PRIVATE_CORE_OAT_NAME := $$(core_oat_name)
@@ -96,7 +102,7 @@
 $$(core_image_name): $$(HOST_CORE_DEX_LOCATIONS) $$(core_dex2oat_dependency)
 	@echo "host dex2oat: $$@"
 	@mkdir -p $$(dir $$@)
-	$$(hide) $$(DEX2OAT) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
+	$$(hide) $(3) $$(DEX2OAT)$(4) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
 	  --runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
 	  --image-classes=$$(PRELOADED_CLASSES) $$(addprefix --dex-file=,$$(HOST_CORE_DEX_FILES)) \
 	  $$(addprefix --dex-location=,$$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
@@ -118,27 +124,35 @@
   core_infix :=
 endef  # create-core-oat-host-rules
 
-# $(1): compiler - optimizing, interpreter or interp-ac (interpreter-access-checks).
-# $(2): multi-image.
+# $(1): compiler - optimizing, interpreter or interpreter-access-checks.
+# $(2): wrapper.
+# $(3): dex2oat suffix.
+# $(4): multi-image.
 define create-core-oat-host-rule-combination
-  $(call create-core-oat-host-rules,$(1),,$(2))
+  $(call create-core-oat-host-rules,$(1),,$(2),$(3),$(4))
 
   ifneq ($(HOST_PREFER_32_BIT),true)
-    $(call create-core-oat-host-rules,$(1),2ND_,$(2))
+    $(call create-core-oat-host-rules,$(1),2ND_,$(2),$(3),$(4))
   endif
 endef
 
-$(eval $(call create-core-oat-host-rule-combination,optimizing,false))
-$(eval $(call create-core-oat-host-rule-combination,interpreter,false))
-$(eval $(call create-core-oat-host-rule-combination,interp-ac,false))
-$(eval $(call create-core-oat-host-rule-combination,optimizing,true))
-$(eval $(call create-core-oat-host-rule-combination,interpreter,true))
-$(eval $(call create-core-oat-host-rule-combination,interp-ac,true))
+$(eval $(call create-core-oat-host-rule-combination,optimizing,,,false))
+$(eval $(call create-core-oat-host-rule-combination,interpreter,,,false))
+$(eval $(call create-core-oat-host-rule-combination,interp-ac,,,false))
+$(eval $(call create-core-oat-host-rule-combination,optimizing,,,true))
+$(eval $(call create-core-oat-host-rule-combination,interpreter,,,true))
+$(eval $(call create-core-oat-host-rule-combination,interp-ac,,,true))
+
+valgrindHOST_CORE_IMG_OUTS :=
+valgrindHOST_CORE_OAT_OUTS :=
+$(eval $(call create-core-oat-host-rule-combination,optimizing,valgrind,32,false))
+$(eval $(call create-core-oat-host-rule-combination,interpreter,valgrind,32,false))
+$(eval $(call create-core-oat-host-rule-combination,interp-ac,valgrind,32,false))
+
+valgrind-test-art-host-dex2oat-host: $(valgrindHOST_CORE_IMG_OUTS)
 
 test-art-host-dex2oat-host: $(HOST_CORE_IMG_OUTS)
 
-# $(1): compiler - optimizing, interpreter or interp-ac (interpreter-access-checks).
-# $(2): 2ND_ or undefined
 define create-core-oat-target-rules
   core_compile_options :=
   core_image_name :=
@@ -162,32 +176,36 @@
   endif
   ifneq ($(filter-out interpreter interp-ac optimizing,$(1)),)
     # Technically this test is not precise, but hopefully good enough.
-    $$(error found $(1) expected interpreter, interp-ac, or optimizing)
+    $$(error found $(1) expected interpreter, interpreter-access-checks, or optimizing)
   endif
 
-  core_image_name := $($(2)TARGET_CORE_IMG_OUT_BASE)$$(core_infix)$(CORE_IMG_SUFFIX)
-  core_oat_name := $($(2)TARGET_CORE_OAT_OUT_BASE)$$(core_infix)$(CORE_OAT_SUFFIX)
+  core_image_name := $($(2)TARGET_CORE_IMG_OUT_BASE)$$(core_infix)$(3)$(CORE_IMG_SUFFIX)
+  core_oat_name := $($(2)TARGET_CORE_OAT_OUT_BASE)$$(core_infix)$(3)$(CORE_OAT_SUFFIX)
 
   # Using the bitness suffix makes it easier to add as a dependency for the run-test mk.
   ifeq ($(2),)
     ifdef TARGET_2ND_ARCH
-      TARGET_CORE_IMAGE_$(1)_64 := $$(core_image_name)
+      $(3)TARGET_CORE_IMAGE_$(1)_64 := $$(core_image_name)
     else
-      TARGET_CORE_IMAGE_$(1)_32 := $$(core_image_name)
+      $(3)TARGET_CORE_IMAGE_$(1)_32 := $$(core_image_name)
     endif
   else
-    TARGET_CORE_IMAGE_$(1)_32 := $$(core_image_name)
+    $(3)TARGET_CORE_IMAGE_$(1)_32 := $$(core_image_name)
   endif
-  TARGET_CORE_IMG_OUTS += $$(core_image_name)
-  TARGET_CORE_OAT_OUTS += $$(core_oat_name)
+  $(3)TARGET_CORE_IMG_OUTS += $$(core_image_name)
+  $(3)TARGET_CORE_OAT_OUTS += $$(core_oat_name)
 
+  # If we have a wrapper, make the target phony.
+  ifneq ($(3),)
+.PHONY: $$(core_image_name)
+  endif
 $$(core_image_name): PRIVATE_CORE_COMPILE_OPTIONS := $$(core_compile_options)
 $$(core_image_name): PRIVATE_CORE_IMG_NAME := $$(core_image_name)
 $$(core_image_name): PRIVATE_CORE_OAT_NAME := $$(core_oat_name)
 $$(core_image_name): $$(TARGET_CORE_DEX_FILES) $$(core_dex2oat_dependency)
 	@echo "target dex2oat: $$@"
 	@mkdir -p $$(dir $$@)
-	$$(hide) $$(DEX2OAT) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
+	$$(hide) $(4) $$(DEX2OAT)$(5) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
 	  --runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
 	  --image-classes=$$(PRELOADED_CLASSES) $$(addprefix --dex-file=,$$(TARGET_CORE_DEX_FILES)) \
 	  $$(addprefix --dex-location=,$$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
@@ -210,18 +228,30 @@
   core_infix :=
 endef  # create-core-oat-target-rules
 
-# $(1): compiler - optimizing, interpreter or interp-ac (interpreter-access-checks).
+# $(1): compiler - optimizing, interpreter or interpreter-access-checks.
+# $(2): wrapper.
+# $(3): dex2oat suffix.
 define create-core-oat-target-rule-combination
-  $(call create-core-oat-target-rules,$(1),)
+  $(call create-core-oat-target-rules,$(1),,$(2),$(3))
 
   ifdef TARGET_2ND_ARCH
-    $(call create-core-oat-target-rules,$(1),2ND_)
+    $(call create-core-oat-target-rules,$(1),2ND_,$(2),$(3))
   endif
 endef
 
-$(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,interp-ac))
+$(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,interp-ac,,))
+
+valgrindTARGET_CORE_IMG_OUTS :=
+valgrindTARGET_CORE_OAT_OUTS :=
+$(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,interp-ac,valgrind,32))
+
+valgrind-test-art-host-dex2oat-target: $(valgrindTARGET_CORE_IMG_OUTS)
+
+valgrind-test-art-host-dex2oat: valgrind-test-art-host-dex2oat-host valgrind-test-art-host-dex2oat-target
 
 # Define a default core image that can be used for things like gtests that
 # need some image to run, but don't otherwise care which image is used.
diff --git a/cmdline/unit.h b/cmdline/unit.h
index f73981f..ad6a03d 100644
--- a/cmdline/unit.h
+++ b/cmdline/unit.h
@@ -21,9 +21,8 @@
 
 // Used for arguments that simply indicate presence (e.g. "-help") without any values.
 struct Unit {
-  // Historical note: We specified a user-defined constructor to avoid
-  // 'Conditional jump or move depends on uninitialised value(s)' errors
-  // when running Valgrind.
+  // Avoid 'Conditional jump or move depends on uninitialised value(s)' errors
+  // when running valgrind by specifying a user-defined constructor.
   Unit() {}
   Unit(const Unit&) = default;
   ~Unit() {}
diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc
index fe8b766..dc044c1 100644
--- a/compiler/dex/inline_method_analyser.cc
+++ b/compiler/dex/inline_method_analyser.cc
@@ -724,8 +724,7 @@
     return false;
   }
   DCHECK_GE(field->GetOffset().Int32Value(), 0);
-  // Historical note: We made sure not to interleave function calls with bit field writes to
-  // placate Valgrind. Bug: 27552451.
+  // Do not interleave function calls with bit field writes to placate valgrind. Bug: 27552451.
   uint32_t field_offset = field->GetOffset().Uint32Value();
   bool is_volatile = field->IsVolatile();
   result->field_idx = field_idx;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 6e618f4..ca84d42 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -636,8 +636,8 @@
     return;
   }
 
-  // Historical note: The `outcome` was initialized to please Valgrind - the compiler can reorder
-  // the return value check with the `outcome` check, b/27651442.
+  // Note: The `outcome` is initialized to please valgrind - the compiler can reorder
+  // the return value check with the `outcome` check, b/27651442 .
   bool outcome = false;
   if (TypeCheckHasKnownOutcome(check_cast->GetTargetClassRTI(), object, &outcome)) {
     if (outcome) {
@@ -682,8 +682,8 @@
     return;
   }
 
-  // Historical note: The `outcome` was initialized to please Valgrind - the compiler can reorder
-  // the return value check with the `outcome` check, b/27651442.
+  // Note: The `outcome` is initialized to please valgrind - the compiler can reorder
+  // the return value check with the `outcome` check, b/27651442 .
   bool outcome = false;
   if (TypeCheckHasKnownOutcome(instruction->GetTargetClassRTI(), object, &outcome)) {
     MaybeRecordStat(stats_, MethodCompilationStat::kRemovedInstanceOf);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 00c893a..6b65aca 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -657,7 +657,7 @@
     // the runtime.
     LogCompletionTime();
 
-    if (!kIsDebugBuild && !(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
+    if (!kIsDebugBuild && !(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
       // We want to just exit on non-debug builds, not bringing the runtime down
       // in an orderly fashion. So release the following fields.
       driver_.release();
@@ -3119,9 +3119,9 @@
 int main(int argc, char** argv) {
   int result = static_cast<int>(art::Dex2oat(argc, argv));
   // Everything was done, do an explicit exit here to avoid running Runtime destructors that take
-  // time (bug 10645725) unless we're a debug or instrumented build or running on a memory tool.
-  // Note: The Dex2Oat class should not destruct the runtime in this case.
-  if (!art::kIsDebugBuild && !art::kIsPGOInstrumentation && !art::kRunningOnMemoryTool) {
+  // time (bug 10645725) unless we're a debug or instrumented build or running on valgrind. Note:
+  // The Dex2Oat class should not destruct the runtime in this case.
+  if (!art::kIsDebugBuild && !art::kIsPGOInstrumentation && (RUNNING_ON_MEMORY_TOOL == 0)) {
     _exit(result);
   }
   return result;
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 1d0735d..2fe16f7 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -472,8 +472,8 @@
 };
 
 TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) {
-  // Native memory usage isn't correctly tracked when running under ASan.
-  TEST_DISABLED_FOR_MEMORY_TOOL();
+  // Native memory usage isn't correctly tracked under sanitization.
+  TEST_DISABLED_FOR_MEMORY_TOOL_ASAN();
 
   // The `native_alloc_2_ >= native_alloc_1_` assertion below may not
   // hold true on some x86 systems; disable this test while we
@@ -1054,6 +1054,8 @@
 }
 
 TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
+  TEST_DISABLED_FOR_MEMORY_TOOL_VALGRIND();  // b/63052624
+
   // The watchdog is independent of dex2oat and will not delete intermediates. It is possible
   // that the compilation succeeds and the file is completely written by the time the watchdog
   // kills dex2oat (but the dex2oat threads must have been scheduled pretty badly).
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 8ae93ff..01726af 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -2083,8 +2083,7 @@
         size_t size = ArtMethod::Size(target_ptr_size_);
         size_t alignment = ArtMethod::Alignment(target_ptr_size_);
         memcpy(dest, pair.first, LengthPrefixedArray<ArtMethod>::ComputeSize(0, size, alignment));
-        // Clear padding to avoid non-deterministic data in the image.
-        // Historical note: We also did that to placate Valgrind.
+        // Clear padding to avoid non-deterministic data in the image (and placate valgrind).
         reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(dest)->ClearPadding(size, alignment);
         break;
       }
diff --git a/libartbase/base/arena_allocator.h b/libartbase/base/arena_allocator.h
index 4ad77ba..211ff4f 100644
--- a/libartbase/base/arena_allocator.h
+++ b/libartbase/base/arena_allocator.h
@@ -147,9 +147,34 @@
 
 typedef ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations> ArenaAllocatorStats;
 
-class ArenaAllocatorMemoryTool {
+template <bool kAvailable, bool kValgrind>
+class ArenaAllocatorMemoryToolCheckImpl {
+  // This is the generic template but since there is a partial specialization
+  // for kValgrind == false, this can be instantiated only for kValgrind == true.
+  static_assert(kValgrind, "This template can be instantiated only for Valgrind.");
+  static_assert(kAvailable, "Valgrind implies memory tool availability.");
+
  public:
-  bool IsRunningOnMemoryTool() { return kMemoryToolIsAvailable; }
+  ArenaAllocatorMemoryToolCheckImpl() : is_running_on_valgrind_(RUNNING_ON_MEMORY_TOOL) { }
+  bool IsRunningOnMemoryTool() { return is_running_on_valgrind_; }
+
+ private:
+  const bool is_running_on_valgrind_;
+};
+
+template <bool kAvailable>
+class ArenaAllocatorMemoryToolCheckImpl<kAvailable, false> {
+ public:
+  ArenaAllocatorMemoryToolCheckImpl() { }
+  bool IsRunningOnMemoryTool() { return kAvailable; }
+};
+
+typedef ArenaAllocatorMemoryToolCheckImpl<kMemoryToolIsAvailable, kMemoryToolIsValgrind>
+    ArenaAllocatorMemoryToolCheck;
+
+class ArenaAllocatorMemoryTool : private ArenaAllocatorMemoryToolCheck {
+ public:
+  using ArenaAllocatorMemoryToolCheck::IsRunningOnMemoryTool;
 
   void MakeDefined(void* ptr, size_t size) {
     if (UNLIKELY(IsRunningOnMemoryTool())) {
diff --git a/libartbase/base/arena_allocator_test.cc b/libartbase/base/arena_allocator_test.cc
index 6323a2b..e358710 100644
--- a/libartbase/base/arena_allocator_test.cc
+++ b/libartbase/base/arena_allocator_test.cc
@@ -16,7 +16,6 @@
 
 #include "arena_allocator-inl.h"
 #include "arena_bit_vector.h"
-#include "base/common_art_test.h"
 #include "gtest/gtest.h"
 #include "malloc_arena_pool.h"
 #include "memory_tool.h"
@@ -147,8 +146,11 @@
 }
 
 TEST_F(ArenaAllocatorTest, ReallocReuse) {
-  // Realloc does not reuse arenas when running under sanitization.
-  TEST_DISABLED_FOR_MEMORY_TOOL();
+  // Realloc does not reuse arenas when running under sanitization. So we cannot do those
+  if (RUNNING_ON_MEMORY_TOOL != 0) {
+    printf("WARNING: TEST DISABLED FOR MEMORY_TOOL\n");
+    return;
+  }
 
   {
     // Case 1: small aligned allocation, aligned extend inside arena.
diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h
index fe988a4..a4764c2 100644
--- a/libartbase/base/common_art_test.h
+++ b/libartbase/base/common_art_test.h
@@ -207,11 +207,23 @@
   }
 
 #define TEST_DISABLED_FOR_MEMORY_TOOL() \
-  if (kRunningOnMemoryTool) { \
+  if (RUNNING_ON_MEMORY_TOOL > 0) { \
     printf("WARNING: TEST DISABLED FOR MEMORY TOOL\n"); \
     return; \
   }
 
+#define TEST_DISABLED_FOR_MEMORY_TOOL_VALGRIND() \
+  if (RUNNING_ON_MEMORY_TOOL > 0 && kMemoryToolIsValgrind) { \
+    printf("WARNING: TEST DISABLED FOR MEMORY TOOL VALGRIND\n"); \
+    return; \
+  }
+
+#define TEST_DISABLED_FOR_MEMORY_TOOL_ASAN() \
+  if (RUNNING_ON_MEMORY_TOOL > 0 && !kMemoryToolIsValgrind) { \
+    printf("WARNING: TEST DISABLED FOR MEMORY TOOL ASAN\n"); \
+    return; \
+  }
+
 #define TEST_DISABLED_FOR_HEAP_POISONING() \
   if (kPoisonHeapReferences) { \
     printf("WARNING: TEST DISABLED FOR HEAP POISONING\n"); \
diff --git a/libartbase/base/malloc_arena_pool.cc b/libartbase/base/malloc_arena_pool.cc
index 15a5d71..144b06c 100644
--- a/libartbase/base/malloc_arena_pool.cc
+++ b/libartbase/base/malloc_arena_pool.cc
@@ -53,7 +53,7 @@
     memory_ = unaligned_memory_;
   } else {
     memory_ = AlignUp(unaligned_memory_, ArenaAllocator::kArenaAlignment);
-    if (kRunningOnMemoryTool) {
+    if (UNLIKELY(RUNNING_ON_MEMORY_TOOL > 0)) {
       size_t head = memory_ - unaligned_memory_;
       size_t tail = overallocation - head;
       MEMORY_TOOL_MAKE_NOACCESS(unaligned_memory_, head);
@@ -66,7 +66,7 @@
 
 MallocArena::~MallocArena() {
   constexpr size_t overallocation = RequiredOverallocation();
-  if (overallocation != 0u && kRunningOnMemoryTool) {
+  if (overallocation != 0u && UNLIKELY(RUNNING_ON_MEMORY_TOOL > 0)) {
     size_t head = memory_ - unaligned_memory_;
     size_t tail = overallocation - head;
     MEMORY_TOOL_MAKE_UNDEFINED(unaligned_memory_, head);
@@ -132,7 +132,7 @@
 }
 
 void MallocArenaPool::FreeArenaChain(Arena* first) {
-  if (kRunningOnMemoryTool) {
+  if (UNLIKELY(RUNNING_ON_MEMORY_TOOL > 0)) {
     for (Arena* arena = first; arena != nullptr; arena = arena->next_) {
       MEMORY_TOOL_MAKE_UNDEFINED(arena->memory_, arena->bytes_allocated_);
     }
diff --git a/libartbase/base/mem_map.cc b/libartbase/base/mem_map.cc
index 9ba1d6c..c455fed 100644
--- a/libartbase/base/mem_map.cc
+++ b/libartbase/base/mem_map.cc
@@ -460,7 +460,7 @@
       (expected_ptr == nullptr) ? nullptr : (expected_ptr - page_offset);
 
   size_t redzone_size = 0;
-  if (kRunningOnMemoryTool && kMemoryToolAddsRedzones && expected_ptr == nullptr) {
+  if (RUNNING_ON_MEMORY_TOOL && kMemoryToolAddsRedzones && expected_ptr == nullptr) {
     redzone_size = kPageSize;
     page_aligned_byte_count += redzone_size;
   }
@@ -649,11 +649,9 @@
 bool MemMap::Sync() {
   bool result;
   if (redzone_size_ != 0) {
-    // To avoid errors when running on a memory tool, temporarily lift the lower-end noaccess
-    // protection before passing it to msync() as it only accepts page-aligned base address,
-    // and exclude the higher-end noaccess protection from the msync range. b/27552451.
-    // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-    // check whether this special case is needed for ASan.
+    // To avoid valgrind errors, temporarily lift the lower-end noaccess protection before passing
+    // it to msync() as it only accepts page-aligned base address, and exclude the higher-end
+    // noaccess protection from the msync range. b/27552451.
     uint8_t* base_begin = reinterpret_cast<uint8_t*>(base_begin_);
     MEMORY_TOOL_MAKE_DEFINED(base_begin, begin_ - base_begin);
     result = msync(BaseBegin(), End() - base_begin, MS_SYNC) == 0;
diff --git a/libartbase/base/mem_map_test.cc b/libartbase/base/mem_map_test.cc
index 4a78bdc..d956126 100644
--- a/libartbase/base/mem_map_test.cc
+++ b/libartbase/base/mem_map_test.cc
@@ -471,33 +471,31 @@
   // cannot allocate in the 2GB-4GB region.
   TEST_DISABLED_FOR_MIPS();
 
-  // This test may not work under Valgrind.
-  // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-  // check whether this test works with ASan.
-  TEST_DISABLED_FOR_MEMORY_TOOL();
-
   CommonInit();
-  constexpr size_t size = 0x100000;
-  // Try all addresses starting from 2GB to 4GB.
-  size_t start_addr = 2 * GB;
-  std::string error_msg;
-  std::unique_ptr<MemMap> map;
-  for (; start_addr <= std::numeric_limits<uint32_t>::max() - size; start_addr += size) {
-    map.reset(MemMap::MapAnonymous("MapAnonymousExactAddr32bitHighAddr",
-                                   reinterpret_cast<uint8_t*>(start_addr),
-                                   size,
-                                   PROT_READ | PROT_WRITE,
-                                   /*low_4gb*/true,
-                                   false,
-                                   &error_msg));
-    if (map != nullptr) {
-      break;
+  // This test may not work under valgrind.
+  if (RUNNING_ON_MEMORY_TOOL == 0) {
+    constexpr size_t size = 0x100000;
+    // Try all addresses starting from 2GB to 4GB.
+    size_t start_addr = 2 * GB;
+    std::string error_msg;
+    std::unique_ptr<MemMap> map;
+    for (; start_addr <= std::numeric_limits<uint32_t>::max() - size; start_addr += size) {
+      map.reset(MemMap::MapAnonymous("MapAnonymousExactAddr32bitHighAddr",
+                                     reinterpret_cast<uint8_t*>(start_addr),
+                                     size,
+                                     PROT_READ | PROT_WRITE,
+                                     /*low_4gb*/true,
+                                     false,
+                                     &error_msg));
+      if (map != nullptr) {
+        break;
+      }
     }
+    ASSERT_TRUE(map.get() != nullptr) << error_msg;
+    ASSERT_GE(reinterpret_cast<uintptr_t>(map->End()), 2u * GB);
+    ASSERT_TRUE(error_msg.empty());
+    ASSERT_EQ(BaseBegin(map.get()), reinterpret_cast<void*>(start_addr));
   }
-  ASSERT_TRUE(map.get() != nullptr) << error_msg;
-  ASSERT_GE(reinterpret_cast<uintptr_t>(map->End()), 2u * GB);
-  ASSERT_TRUE(error_msg.empty());
-  ASSERT_EQ(BaseBegin(map.get()), reinterpret_cast<void*>(start_addr));
 }
 
 TEST_F(MemMapTest, MapAnonymousOverflow) {
diff --git a/libartbase/base/memory_tool.h b/libartbase/base/memory_tool.h
index d381f01..e1df99f 100644
--- a/libartbase/base/memory_tool.h
+++ b/libartbase/base/memory_tool.h
@@ -19,53 +19,53 @@
 
 #include <stddef.h>
 
-namespace art {
-
 #if !defined(__has_feature)
-# define __has_feature(x) 0
+#define __has_feature(x) 0
 #endif
 
 #if __has_feature(address_sanitizer)
 
-# include <sanitizer/asan_interface.h>
-# define ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#define ADDRESS_SANITIZER
 
-# ifdef ART_ENABLE_ADDRESS_SANITIZER
-#  define MEMORY_TOOL_MAKE_NOACCESS(p, s) __asan_poison_memory_region(p, s)
-#  define MEMORY_TOOL_MAKE_UNDEFINED(p, s) __asan_unpoison_memory_region(p, s)
-#  define MEMORY_TOOL_MAKE_DEFINED(p, s) __asan_unpoison_memory_region(p, s)
+#ifdef ART_ENABLE_ADDRESS_SANITIZER
+#define MEMORY_TOOL_MAKE_NOACCESS(p, s) __asan_poison_memory_region(p, s)
+#define MEMORY_TOOL_MAKE_UNDEFINED(p, s) __asan_unpoison_memory_region(p, s)
+#define MEMORY_TOOL_MAKE_DEFINED(p, s) __asan_unpoison_memory_region(p, s)
 constexpr bool kMemoryToolIsAvailable = true;
-# else
-#  define MEMORY_TOOL_MAKE_NOACCESS(p, s) do { (void)(p); (void)(s); } while (0)
-#  define MEMORY_TOOL_MAKE_UNDEFINED(p, s) do { (void)(p); (void)(s); } while (0)
-#  define MEMORY_TOOL_MAKE_DEFINED(p, s) do { (void)(p); (void)(s); } while (0)
+#else
+#define MEMORY_TOOL_MAKE_NOACCESS(p, s) do { (void)(p); (void)(s); } while (0)
+#define MEMORY_TOOL_MAKE_UNDEFINED(p, s) do { (void)(p); (void)(s); } while (0)
+#define MEMORY_TOOL_MAKE_DEFINED(p, s) do { (void)(p); (void)(s); } while (0)
 constexpr bool kMemoryToolIsAvailable = false;
-# endif
+#endif
 
 extern "C" void __asan_handle_no_return();
 
-# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
-# define MEMORY_TOOL_HANDLE_NO_RETURN __asan_handle_no_return()
-constexpr bool kRunningOnMemoryTool = true;
+#define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+#define MEMORY_TOOL_HANDLE_NO_RETURN __asan_handle_no_return()
+#define RUNNING_ON_MEMORY_TOOL 1U
+constexpr bool kMemoryToolIsValgrind = false;
 constexpr bool kMemoryToolDetectsLeaks = true;
 constexpr bool kMemoryToolAddsRedzones = true;
 constexpr size_t kMemoryToolStackGuardSizeScale = 2;
 
 #else
 
-# define MEMORY_TOOL_MAKE_NOACCESS(p, s) do { (void)(p); (void)(s); } while (0)
-# define MEMORY_TOOL_MAKE_UNDEFINED(p, s) do { (void)(p); (void)(s); } while (0)
-# define MEMORY_TOOL_MAKE_DEFINED(p, s) do { (void)(p); (void)(s); } while (0)
-# define ATTRIBUTE_NO_SANITIZE_ADDRESS
-# define MEMORY_TOOL_HANDLE_NO_RETURN do { } while (0)
-constexpr bool kRunningOnMemoryTool = false;
-constexpr bool kMemoryToolIsAvailable = false;
-constexpr bool kMemoryToolDetectsLeaks = false;
-constexpr bool kMemoryToolAddsRedzones = false;
+#include <memcheck/memcheck.h>
+#include <valgrind.h>
+#define MEMORY_TOOL_MAKE_NOACCESS(p, s) VALGRIND_MAKE_MEM_NOACCESS(p, s)
+#define MEMORY_TOOL_MAKE_UNDEFINED(p, s) VALGRIND_MAKE_MEM_UNDEFINED(p, s)
+#define MEMORY_TOOL_MAKE_DEFINED(p, s) VALGRIND_MAKE_MEM_DEFINED(p, s)
+#define ATTRIBUTE_NO_SANITIZE_ADDRESS
+#define MEMORY_TOOL_HANDLE_NO_RETURN do { } while (0)
+#define RUNNING_ON_MEMORY_TOOL RUNNING_ON_VALGRIND
+constexpr bool kMemoryToolIsAvailable = true;
+constexpr bool kMemoryToolIsValgrind = true;
+constexpr bool kMemoryToolDetectsLeaks = true;
+constexpr bool kMemoryToolAddsRedzones = true;
 constexpr size_t kMemoryToolStackGuardSizeScale = 1;
 
 #endif
 
-}  // namespace art
-
 #endif  // ART_LIBARTBASE_BASE_MEMORY_TOOL_H_
diff --git a/libartbase/base/scoped_arena_containers.h b/libartbase/base/scoped_arena_containers.h
index 679bcc0..4193981 100644
--- a/libartbase/base/scoped_arena_containers.h
+++ b/libartbase/base/scoped_arena_containers.h
@@ -228,7 +228,7 @@
  protected:
   // Used for variable sized objects such as RegisterLine.
   ALWAYS_INLINE void ProtectMemory(T* ptr, size_t size) const {
-    if (kRunningOnMemoryTool) {
+    if (RUNNING_ON_MEMORY_TOOL > 0) {
       // Writing to the memory will fail ift we already destroyed the pointer with
       // DestroyOnlyDelete since we make it no access.
       memset(ptr, kMagicFill, size);
diff --git a/libdexfile/dex/dex_file_tracking_registrar.cc b/libdexfile/dex/dex_file_tracking_registrar.cc
index 551bea1..78ea9c1 100644
--- a/libdexfile/dex/dex_file_tracking_registrar.cc
+++ b/libdexfile/dex/dex_file_tracking_registrar.cc
@@ -130,8 +130,7 @@
     MEMORY_TOOL_MAKE_NOACCESS(begin, size);
   } else {
     // Note: MEMORY_TOOL_MAKE_UNDEFINED has the same functionality with Address
-    // Sanitizer.
-    // Historical note: The difference has not been tested with Valgrind.
+    // Sanitizer. The difference has not been tested with Valgrind
     MEMORY_TOOL_MAKE_DEFINED(begin, size);
   }
 }
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 0889a8e..dc9d990 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -610,7 +610,7 @@
     }
   }
 
-  if (!kIsDebugBuild && !(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
+  if (!kIsDebugBuild && !(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
     // We want to just exit on non-debug builds, not bringing the runtime down
     // in an orderly fashion. So release the following fields.
     runtime.release();
@@ -690,7 +690,7 @@
     }
   }
 
-  if (!kIsDebugBuild && !(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
+  if (!kIsDebugBuild && !(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
     // We want to just exit on non-debug builds, not bringing the runtime down
     // in an orderly fashion. So release the following fields.
     runtime.release();
diff --git a/runtime/base/mem_map_arena_pool.cc b/runtime/base/mem_map_arena_pool.cc
index 702f0e4..9ac7886 100644
--- a/runtime/base/mem_map_arena_pool.cc
+++ b/runtime/base/mem_map_arena_pool.cc
@@ -125,7 +125,7 @@
 }
 
 void MemMapArenaPool::FreeArenaChain(Arena* first) {
-  if (kRunningOnMemoryTool) {
+  if (UNLIKELY(RUNNING_ON_MEMORY_TOOL > 0)) {
     for (Arena* arena = first; arena != nullptr; arena = arena->next_) {
       MEMORY_TOOL_MAKE_UNDEFINED(arena->memory_, arena->bytes_allocated_);
     }
diff --git a/runtime/exec_utils_test.cc b/runtime/exec_utils_test.cc
index a9c1ea2..68edfa8 100644
--- a/runtime/exec_utils_test.cc
+++ b/runtime/exec_utils_test.cc
@@ -36,10 +36,8 @@
     command.push_back("/usr/bin/id");
   }
   std::string error_msg;
-  if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
-    // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
-    // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-    // check whether the following code works with ASan.
+  if (!(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
+    // Running on valgrind fails due to some memory that leaks in thread alternate signal stacks.
     EXPECT_TRUE(Exec(command, &error_msg));
   }
   EXPECT_EQ(0U, error_msg.size()) << error_msg;
@@ -52,10 +50,8 @@
   std::vector<std::string> command;
   command.push_back("bogus");
   std::string error_msg;
-  if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
-    // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
-    // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-    // check whether the following code works with ASan.
+  if (!(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
+    // Running on valgrind fails due to some memory that leaks in thread alternate signal stacks.
     EXPECT_FALSE(Exec(command, &error_msg));
     EXPECT_FALSE(error_msg.empty());
   }
@@ -76,10 +72,8 @@
   }
   command.push_back(kModifiedVariable);
   std::string error_msg;
-  if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
-    // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
-    // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-    // check whether the following code works with ASan.
+  if (!(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
+    // Running on valgrind fails due to some memory that leaks in thread alternate signal stacks.
     EXPECT_FALSE(Exec(command, &error_msg));
     EXPECT_NE(0U, error_msg.size()) << error_msg;
   }
@@ -103,10 +97,8 @@
   }
   command.push_back(kDeletedVariable);
   std::string error_msg;
-  if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
-    // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
-    // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-    // check whether the following code works with ASan.
+  if (!(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
+    // Running on valgrind fails due to some memory that leaks in thread alternate signal stacks.
     EXPECT_TRUE(Exec(command, &error_msg));
     EXPECT_EQ(0U, error_msg.size()) << error_msg;
   }
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 30213d5..150fe95 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -625,7 +625,7 @@
 
   // If true, check that the returned memory is actually zero.
   static constexpr bool kCheckZeroMemory = kIsDebugBuild;
-  // Do not check memory when running under a memory tool. In a normal
+  // Valgrind protects memory, so do not check memory when running under valgrind. In a normal
   // build with kCheckZeroMemory the whole test should be optimized away.
   // TODO: Unprotect before checks.
   ALWAYS_INLINE bool ShouldCheckZeroMemory();
@@ -768,7 +768,7 @@
   // greater than or equal to this value, release pages.
   const size_t page_release_size_threshold_;
 
-  // Whether this allocator is running on a memory tool.
+  // Whether this allocator is running under Valgrind.
   bool is_running_on_memory_tool_;
 
   // The base address of the memory region that's managed by this allocator.
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 6756868..948d233 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -272,7 +272,7 @@
     }
     case kAllocatorTypeRosAlloc: {
       if (kInstrumented && UNLIKELY(is_running_on_memory_tool_)) {
-        // If running on ASan, we should be using the instrumented path.
+        // If running on valgrind or asan, we should be using the instrumented path.
         size_t max_bytes_tl_bulk_allocated = rosalloc_space_->MaxBytesBulkAllocatedFor(alloc_size);
         if (UNLIKELY(IsOutOfMemoryOnAllocation(allocator_type,
                                                max_bytes_tl_bulk_allocated,
@@ -303,7 +303,7 @@
     }
     case kAllocatorTypeDlMalloc: {
       if (kInstrumented && UNLIKELY(is_running_on_memory_tool_)) {
-        // If running on ASan, we should be using the instrumented path.
+        // If running on valgrind, we should be using the instrumented path.
         ret = dlmalloc_space_->Alloc(self,
                                      alloc_size,
                                      bytes_allocated,
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 12021b7..b004566 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2248,8 +2248,7 @@
       // Add a new bin with the remaining space.
       AddBin(size - alloc_size, pos + alloc_size);
     }
-    // Copy the object over to its new location.
-    // Historical note: We did not use `alloc_size` to avoid a Valgrind error.
+    // Copy the object over to its new location. Don't use alloc_size to avoid valgrind error.
     memcpy(reinterpret_cast<void*>(forward_address), obj, obj_size);
     if (kUseBakerReadBarrier) {
       obj->AssertReadBarrierState();
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index a24ca32..512cde4 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -45,9 +45,8 @@
   }
 
   ~MemoryToolLargeObjectMapSpace() OVERRIDE {
-    // Historical note: We were deleting large objects to keep Valgrind happy if there were
-    // any large objects such as Dex cache arrays which aren't freed since they are held live
-    // by the class linker.
+    // Keep valgrind happy if there is any large objects such as dex cache arrays which aren't
+    // freed since they are held live by the class linker.
     MutexLock mu(Thread::Current(), lock_);
     for (auto& m : large_objects_) {
       delete m.second.mem_map;
diff --git a/runtime/gc/space/memory_tool_malloc_space-inl.h b/runtime/gc/space/memory_tool_malloc_space-inl.h
index c022171..8282f3d 100644
--- a/runtime/gc/space/memory_tool_malloc_space-inl.h
+++ b/runtime/gc/space/memory_tool_malloc_space-inl.h
@@ -30,14 +30,11 @@
 namespace memory_tool_details {
 
 template <size_t kMemoryToolRedZoneBytes, bool kUseObjSizeForUsable>
-inline mirror::Object* AdjustForMemoryTool(void* obj_with_rdz,
-                                           size_t num_bytes,
-                                           size_t bytes_allocated,
-                                           size_t usable_size,
-                                           size_t bytes_tl_bulk_allocated,
-                                           size_t* bytes_allocated_out,
-                                           size_t* usable_size_out,
-                                           size_t* bytes_tl_bulk_allocated_out) {
+inline mirror::Object* AdjustForValgrind(void* obj_with_rdz, size_t num_bytes,
+                                         size_t bytes_allocated, size_t usable_size,
+                                         size_t bytes_tl_bulk_allocated,
+                                         size_t* bytes_allocated_out, size_t* usable_size_out,
+                                         size_t* bytes_tl_bulk_allocated_out) {
   if (bytes_allocated_out != nullptr) {
     *bytes_allocated_out = bytes_allocated;
   }
@@ -87,31 +84,24 @@
           bool kUseObjSizeForUsable>
 mirror::Object*
 MemoryToolMallocSpace<S,
-                      kMemoryToolRedZoneBytes,
-                      kAdjustForRedzoneInAllocSize,
-                      kUseObjSizeForUsable>::AllocWithGrowth(
-    Thread* self,
-    size_t num_bytes,
-    size_t* bytes_allocated_out,
-    size_t* usable_size_out,
+                    kMemoryToolRedZoneBytes,
+                    kAdjustForRedzoneInAllocSize,
+                    kUseObjSizeForUsable>::AllocWithGrowth(
+    Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out,
     size_t* bytes_tl_bulk_allocated_out) {
   size_t bytes_allocated;
   size_t usable_size;
   size_t bytes_tl_bulk_allocated;
-  void* obj_with_rdz = S::AllocWithGrowth(self,
-                                          num_bytes + 2 * kMemoryToolRedZoneBytes,
-                                          &bytes_allocated,
-                                          &usable_size,
+  void* obj_with_rdz = S::AllocWithGrowth(self, num_bytes + 2 * kMemoryToolRedZoneBytes,
+                                          &bytes_allocated, &usable_size,
                                           &bytes_tl_bulk_allocated);
   if (obj_with_rdz == nullptr) {
     return nullptr;
   }
 
-  return memory_tool_details::AdjustForMemoryTool<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
-      obj_with_rdz,
-      num_bytes,
-      bytes_allocated,
-      usable_size,
+  return memory_tool_details::AdjustForValgrind<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
+      obj_with_rdz, num_bytes,
+      bytes_allocated, usable_size,
       bytes_tl_bulk_allocated,
       bytes_allocated_out,
       usable_size_out,
@@ -123,35 +113,27 @@
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
 mirror::Object* MemoryToolMallocSpace<S,
-                                      kMemoryToolRedZoneBytes,
-                                      kAdjustForRedzoneInAllocSize,
-                                      kUseObjSizeForUsable>::Alloc(
-    Thread* self,
-    size_t num_bytes,
-    size_t* bytes_allocated_out,
-    size_t* usable_size_out,
+                                    kMemoryToolRedZoneBytes,
+                                    kAdjustForRedzoneInAllocSize,
+                                    kUseObjSizeForUsable>::Alloc(
+    Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out,
     size_t* bytes_tl_bulk_allocated_out) {
   size_t bytes_allocated;
   size_t usable_size;
   size_t bytes_tl_bulk_allocated;
-  void* obj_with_rdz = S::Alloc(self,
-                                num_bytes + 2 * kMemoryToolRedZoneBytes,
-                                &bytes_allocated,
-                                &usable_size,
-                                &bytes_tl_bulk_allocated);
+  void* obj_with_rdz = S::Alloc(self, num_bytes + 2 * kMemoryToolRedZoneBytes,
+                                &bytes_allocated, &usable_size, &bytes_tl_bulk_allocated);
   if (obj_with_rdz == nullptr) {
     return nullptr;
   }
 
-  return memory_tool_details::AdjustForMemoryTool<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
-      obj_with_rdz,
-      num_bytes,
-      bytes_allocated,
-      usable_size,
-      bytes_tl_bulk_allocated,
-      bytes_allocated_out,
-      usable_size_out,
-      bytes_tl_bulk_allocated_out);
+  return memory_tool_details::AdjustForValgrind<kMemoryToolRedZoneBytes,
+                                             kUseObjSizeForUsable>(obj_with_rdz, num_bytes,
+                                                                   bytes_allocated, usable_size,
+                                                                   bytes_tl_bulk_allocated,
+                                                                   bytes_allocated_out,
+                                                                   usable_size_out,
+                                                                   bytes_tl_bulk_allocated_out);
 }
 
 template <typename S,
@@ -159,31 +141,24 @@
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
 mirror::Object* MemoryToolMallocSpace<S,
-                                      kMemoryToolRedZoneBytes,
-                                      kAdjustForRedzoneInAllocSize,
-                                      kUseObjSizeForUsable>::AllocThreadUnsafe(
-    Thread* self,
-    size_t num_bytes,
-    size_t* bytes_allocated_out,
-    size_t* usable_size_out,
+                                    kMemoryToolRedZoneBytes,
+                                    kAdjustForRedzoneInAllocSize,
+                                    kUseObjSizeForUsable>::AllocThreadUnsafe(
+    Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out,
     size_t* bytes_tl_bulk_allocated_out) {
   size_t bytes_allocated;
   size_t usable_size;
   size_t bytes_tl_bulk_allocated;
-  void* obj_with_rdz = S::AllocThreadUnsafe(self,
-                                            num_bytes + 2 * kMemoryToolRedZoneBytes,
-                                            &bytes_allocated,
-                                            &usable_size,
+  void* obj_with_rdz = S::AllocThreadUnsafe(self, num_bytes + 2 * kMemoryToolRedZoneBytes,
+                                            &bytes_allocated, &usable_size,
                                             &bytes_tl_bulk_allocated);
   if (obj_with_rdz == nullptr) {
     return nullptr;
   }
 
-  return memory_tool_details::AdjustForMemoryTool<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
-      obj_with_rdz,
-      num_bytes,
-      bytes_allocated,
-      usable_size,
+  return memory_tool_details::AdjustForValgrind<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
+      obj_with_rdz, num_bytes,
+      bytes_allocated, usable_size,
       bytes_tl_bulk_allocated,
       bytes_allocated_out,
       usable_size_out,
@@ -195,14 +170,12 @@
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
 size_t MemoryToolMallocSpace<S,
-                             kMemoryToolRedZoneBytes,
-                             kAdjustForRedzoneInAllocSize,
-                             kUseObjSizeForUsable>::AllocationSize(
+                           kMemoryToolRedZoneBytes,
+                           kAdjustForRedzoneInAllocSize,
+                           kUseObjSizeForUsable>::AllocationSize(
     mirror::Object* obj, size_t* usable_size) {
-  size_t result = S::AllocationSize(
-      reinterpret_cast<mirror::Object*>(
-          reinterpret_cast<uint8_t*>(obj)
-              - (kAdjustForRedzoneInAllocSize ? kMemoryToolRedZoneBytes : 0)),
+  size_t result = S::AllocationSize(reinterpret_cast<mirror::Object*>(
+      reinterpret_cast<uint8_t*>(obj) - (kAdjustForRedzoneInAllocSize ? kMemoryToolRedZoneBytes : 0)),
       usable_size);
   if (usable_size != nullptr) {
     if (kUseObjSizeForUsable) {
@@ -219,9 +192,10 @@
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
 size_t MemoryToolMallocSpace<S,
-                             kMemoryToolRedZoneBytes,
-                             kAdjustForRedzoneInAllocSize,
-                             kUseObjSizeForUsable>::Free(Thread* self, mirror::Object* ptr) {
+                           kMemoryToolRedZoneBytes,
+                           kAdjustForRedzoneInAllocSize,
+                           kUseObjSizeForUsable>::Free(
+    Thread* self, mirror::Object* ptr) {
   void* obj_after_rdz = reinterpret_cast<void*>(ptr);
   uint8_t* obj_with_rdz = reinterpret_cast<uint8_t*>(obj_after_rdz) - kMemoryToolRedZoneBytes;
 
@@ -246,10 +220,10 @@
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
 size_t MemoryToolMallocSpace<S,
-                             kMemoryToolRedZoneBytes,
-                             kAdjustForRedzoneInAllocSize,
-                             kUseObjSizeForUsable>::FreeList(
-                                 Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
+                           kMemoryToolRedZoneBytes,
+                           kAdjustForRedzoneInAllocSize,
+                           kUseObjSizeForUsable>::FreeList(
+    Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
   size_t freed = 0;
   for (size_t i = 0; i < num_ptrs; i++) {
     freed += Free(self, ptrs[i]);
@@ -264,12 +238,11 @@
           bool kUseObjSizeForUsable>
 template <typename... Params>
 MemoryToolMallocSpace<S,
-                      kMemoryToolRedZoneBytes,
-                      kAdjustForRedzoneInAllocSize,
-                      kUseObjSizeForUsable>::MemoryToolMallocSpace(
-                          MemMap* mem_map, size_t initial_size, Params... params)
-                          : S(mem_map, initial_size, params...) {
-  // Don't want to change the memory tool states of the mem map here as the allocator is already
+                    kMemoryToolRedZoneBytes,
+                    kAdjustForRedzoneInAllocSize,
+                    kUseObjSizeForUsable>::MemoryToolMallocSpace(
+    MemMap* mem_map, size_t initial_size, Params... params) : S(mem_map, initial_size, params...) {
+  // Don't want to change the valgrind states of the mem map here as the allocator is already
   // initialized at this point and that may interfere with what the allocator does internally. Note
   // that the tail beyond the initial size is mprotected.
 }
@@ -279,9 +252,9 @@
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
 size_t MemoryToolMallocSpace<S,
-                             kMemoryToolRedZoneBytes,
-                             kAdjustForRedzoneInAllocSize,
-                             kUseObjSizeForUsable>::MaxBytesBulkAllocatedFor(size_t num_bytes) {
+                           kMemoryToolRedZoneBytes,
+                           kAdjustForRedzoneInAllocSize,
+                           kUseObjSizeForUsable>::MaxBytesBulkAllocatedFor(size_t num_bytes) {
   return S::MaxBytesBulkAllocatedFor(num_bytes + 2 * kMemoryToolRedZoneBytes);
 }
 
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index d698cf2..e786536 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -77,7 +77,7 @@
 
   // Everything is set so record in immutable structure and leave
   uint8_t* begin = mem_map->Begin();
-  // TODO: Fix RosAllocSpace to support ASan. There is currently some issues with
+  // TODO: Fix RosAllocSpace to support Valgrind/ASan. There is currently some issues with
   // AllocationSize caused by redzones. b/12944686
   if (running_on_memory_tool) {
     return new MemoryToolMallocSpace<RosAllocSpace, kDefaultMemoryToolRedZoneBytes, false, true>(
@@ -382,12 +382,12 @@
   size_t size = obj->SizeOf<kVerifyNone>();
   bool add_redzones = false;
   if (kMaybeIsRunningOnMemoryTool) {
-    add_redzones = kRunningOnMemoryTool ? kMemoryToolAddsRedzones : 0;
+    add_redzones = RUNNING_ON_MEMORY_TOOL ? kMemoryToolAddsRedzones : 0;
     if (add_redzones) {
       size += 2 * kDefaultMemoryToolRedZoneBytes;
     }
   } else {
-    DCHECK(!kRunningOnMemoryTool);
+    DCHECK_EQ(RUNNING_ON_MEMORY_TOOL, 0U);
   }
   size_t size_by_size = rosalloc_->UsableSize(size);
   if (kIsDebugBuild) {
diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h
index 4c17233..9d16b87 100644
--- a/runtime/gc/space/rosalloc_space.h
+++ b/runtime/gc/space/rosalloc_space.h
@@ -159,8 +159,8 @@
 
   void* CreateAllocator(void* base, size_t morecore_start, size_t initial_size,
                         size_t maximum_size, bool low_memory_mode) OVERRIDE {
-    return CreateRosAlloc(
-        base, morecore_start, initial_size, maximum_size, low_memory_mode, kRunningOnMemoryTool);
+    return CreateRosAlloc(base, morecore_start, initial_size, maximum_size, low_memory_mode,
+                          RUNNING_ON_MEMORY_TOOL != 0);
   }
   static allocator::RosAlloc* CreateRosAlloc(void* base, size_t morecore_start, size_t initial_size,
                                              size_t maximum_size, bool low_memory_mode,
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index aeb5f4b..fd43562 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -864,6 +864,11 @@
 }
 
 TEST_F(UnstartedRuntimeTest, Pow) {
+  // Valgrind seems to get this wrong, actually. Disable for valgrind.
+  if (RUNNING_ON_MEMORY_TOOL != 0 && kMemoryToolIsValgrind) {
+    return;
+  }
+
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
 
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 736729c..5d4b9e8 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -332,7 +332,7 @@
     }
 
     // When running sanitized, let all tasks finish to not leak. Otherwise just clear the queue.
-    if (!kRunningOnMemoryTool) {
+    if (!RUNNING_ON_MEMORY_TOOL) {
       pool->StopWorkers(self);
       pool->RemoveAllTasks(self);
     }
diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc
index b3a47c3..14f3f45 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -289,10 +289,8 @@
                      ArtMethod* current_method,
                      void* ucontext_ptr,
                      bool skip_frames) {
-  // Historical note: This was disabled when running under Valgrind (b/18119146).
-  // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-  // check whether this test works with ASan.
-  if (kRunningOnMemoryTool) {
+  // b/18119146
+  if (RUNNING_ON_MEMORY_TOOL != 0) {
     return;
   }
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 9196eb2..1402749 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -239,7 +239,7 @@
       exit_(nullptr),
       abort_(nullptr),
       stats_enabled_(false),
-      is_running_on_memory_tool_(kRunningOnMemoryTool),
+      is_running_on_memory_tool_(RUNNING_ON_MEMORY_TOOL),
       instrumentation_(),
       main_thread_group_(nullptr),
       system_thread_group_(nullptr),
@@ -1349,10 +1349,8 @@
     case InstructionSet::kMips:
     case InstructionSet::kMips64:
       implicit_null_checks_ = true;
-      // Installing stack protection does not play well with Valgrind.
-      // TODO: Valgrind is no longer supported, but Address Sanitizer is:
-      // check whether setting `implicit_so_checks_` to `true` works with ASan.
-      implicit_so_checks_ = !kRunningOnMemoryTool;
+      // Installing stack protection does not play well with valgrind.
+      implicit_so_checks_ = !(RUNNING_ON_MEMORY_TOOL && kMemoryToolIsValgrind);
       break;
     default:
       // Keep the defaults.
@@ -1367,8 +1365,8 @@
       // These need to be in a specific order.  The null point check handler must be
       // after the suspend check and stack overflow check handlers.
       //
-      // Note: the instances attach themselves to the fault manager and are handled by it. The
-      //       manager will delete the instance on Shutdown().
+      // Note: the instances attach themselves to the fault manager and are handled by it. The manager
+      //       will delete the instance on Shutdown().
       if (implicit_suspend_checks_) {
         new SuspensionHandler(&fault_manager);
       }
diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc
index 54769f9..72d9919 100644
--- a/runtime/runtime_callbacks_test.cc
+++ b/runtime/runtime_callbacks_test.cc
@@ -339,8 +339,8 @@
 };
 
 TEST_F(RuntimeSigQuitCallbackRuntimeCallbacksTest, SigQuit) {
-  // SigQuit induces a dump. ASan isn't happy with libunwind reading memory.
-  TEST_DISABLED_FOR_MEMORY_TOOL();
+  // SigQuit induces a dump. ASAN isn't happy with libunwind reading memory.
+  TEST_DISABLED_FOR_MEMORY_TOOL_ASAN();
 
   // The runtime needs to be started for the signal handler.
   Thread* self = Thread::Current();
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 2275dae..81ed722 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1115,10 +1115,21 @@
   Runtime* runtime = Runtime::Current();
   bool implicit_stack_check = !runtime->ExplicitStackOverflowChecks() && !runtime->IsAotCompiler();
 
+  // Valgrind on arm doesn't give the right values here. Do not install the guard page, and
+  // effectively disable stack overflow checks (we'll get segfaults, potentially) by setting
+  // stack_begin to 0.
+  const bool valgrind_on_arm =
+      (kRuntimeISA == InstructionSet::kArm || kRuntimeISA == InstructionSet::kArm64) &&
+      kMemoryToolIsValgrind &&
+      RUNNING_ON_MEMORY_TOOL != 0;
+  if (valgrind_on_arm) {
+    tlsPtr_.stack_begin = nullptr;
+  }
+
   ResetDefaultStackEnd();
 
   // Install the protected region if we are doing implicit overflow checks.
-  if (implicit_stack_check) {
+  if (implicit_stack_check && !valgrind_on_arm) {
     // The thread might have protected region at the bottom.  We need
     // to install our own region so we need to move the limits
     // of the stack to make room for it.
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index a4d0d0c..49db0c8 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -111,6 +111,8 @@
     jint,
     jboolean) {
 #if __linux__
+  // TODO: What to do on Valgrind?
+
   std::unique_ptr<Backtrace> bt(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, GetTid()));
   if (!bt->Unwind(0, nullptr)) {
     printf("Cannot unwind in process.\n");
@@ -186,6 +188,7 @@
     jboolean,
     jint pid_int) {
 #if __linux__
+  // TODO: What to do on Valgrind?
   pid_t pid = static_cast<pid_t>(pid_int);
 
   // OK, this is painful. debuggerd uses ptrace to unwind other processes.
diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py
index faa4d91..e0757ab 100644
--- a/test/testrunner/target_config.py
+++ b/test/testrunner/target_config.py
@@ -266,16 +266,14 @@
         }
     },
     'art-gtest-valgrind32': {
-      # Disabled: Valgrind is no longer supported.
-      # Historical note: This was already disabled, as x86 valgrind did not understand SSE4.x
+      # Disabled: x86 valgrind does not understand SSE4.x
       # 'make' : 'valgrind-test-art-host32',
         'env': {
             'ART_USE_READ_BARRIER' : 'false'
         }
     },
     'art-gtest-valgrind64': {
-      # Disabled: Valgrind is no longer supported.
-      # 'make' : 'valgrind-test-art-host64',
+        'make' : 'valgrind-test-art-host64',
         'env': {
             'ART_USE_READ_BARRIER' : 'false'
         }
diff --git a/test/valgrind-suppressions.txt b/test/valgrind-suppressions.txt
new file mode 100644
index 0000000..a97d03c
--- /dev/null
+++ b/test/valgrind-suppressions.txt
@@ -0,0 +1,87 @@
+{
+   b/27596582
+   Memcheck:Cond
+   fun:index
+   fun:expand_dynamic_string_token
+   fun:_dl_map_object
+   fun:map_doit
+   fun:_dl_catch_error
+   fun:do_preload
+   fun:dl_main
+   fun:_dl_sysdep_start
+   fun:_dl_start_final
+   fun:_dl_start
+   obj:/lib/x86_64-linux-gnu/ld-2.19.so
+}
+
+{
+   b/31275764
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:malloc
+   ...
+   fun:_ZN3art7Runtime17InitNativeMethodsEv
+}
+
+# SigQuit runs libbacktrace
+{
+   BackTraceReading64
+   Memcheck:Addr8
+   fun:access_mem_unrestricted
+   fun:_Uelf64_memory_read
+   fun:_Uelf64_valid_object_memory
+   fun:map_create_list
+   fun:unw_map_local_create
+   fun:_ZN14UnwindMapLocal5BuildEv
+   fun:_ZN12BacktraceMap6CreateEib
+}
+{
+   BackTraceReading32
+   Memcheck:Addr4
+   fun:access_mem_unrestricted
+   fun:_Uelf32_memory_read
+   fun:_Uelf32_valid_object_memory
+   fun:map_create_list
+   fun:unw_map_local_create
+   fun:_ZN14UnwindMapLocal5BuildEv
+   fun:_ZN12BacktraceMap6CreateEib
+}
+{
+   BackTraceReading64
+   Memcheck:Addr8
+   fun:access_mem_unrestricted
+   fun:_Uelf64_memory_read
+   fun:_Uelf64_get_load_base
+   fun:map_create_list
+   fun:unw_map_local_create
+   fun:_ZN14UnwindMapLocal5BuildEv
+   fun:_ZN12BacktraceMap6CreateEib
+}
+{
+   BackTraceReading32
+   Memcheck:Addr4
+   fun:access_mem_unrestricted
+   fun:_Uelf32_memory_read
+   fun:_Uelf32_get_load_base
+   fun:map_create_list
+   fun:unw_map_local_create
+   fun:_ZN14UnwindMapLocal5BuildEv
+   fun:_ZN12BacktraceMap6CreateEib
+}
+
+{
+   process_vm_readv
+   Memcheck:Param
+   process_vm_readv(lvec[...])
+   fun:process_vm_readv
+}
+
+# Suppressions for IsAddressMapped check in MemMapTest
+{
+   MemMapTest_IsAddressMapped
+   Memcheck:Param
+   msync(start)
+   ...
+   fun:_ZN3art10MemMapTest15IsAddressMappedEPv
+   ...
+}
diff --git a/test/valgrind-target-suppressions.txt b/test/valgrind-target-suppressions.txt
new file mode 100644
index 0000000..0d63a1c
--- /dev/null
+++ b/test/valgrind-target-suppressions.txt
@@ -0,0 +1,76 @@
+# Valgrind does not recognize the ashmen ioctl() calls on ARM64, so it assumes that a size
+# parameter is a pointer.
+{
+   ashmem ioctl
+   Memcheck:Param
+   ioctl(generic)
+   ...
+   fun:ioctl
+   fun:ashmem_create_region
+}
+
+# It seems that on ARM64 Valgrind considers the canary value used by the Clang stack protector to
+# be an uninitialized value.
+{
+   jemalloc chunk_alloc_cache
+   Memcheck:Cond
+   fun:je_chunk_alloc_cache
+}
+
+# The VectorImpl class does not hold a pointer to the allocated SharedBuffer structure, but to the
+# beginning of the data, which is effectively an interior pointer. Valgrind has limitations when
+# dealing with interior pointers.
+{
+   VectorImpl
+   Memcheck:Leak
+   match-leak-kinds:possible
+   fun:malloc
+   # The wildcards make this rule work both for 32-bit and 64-bit environments.
+   fun:_ZN7android12SharedBuffer5allocE?
+   fun:_ZN7android10VectorImpl5_growE??
+}
+
+# Clang/LLVM uses memcpy for *x = *y, even though x == y (which is undefined behavior). Ignore.
+# b/29279679, https://llvm.org/bugs/show_bug.cgi?id=11763
+{
+   MemCpySelfAssign
+   Memcheck:Overlap
+   fun:memcpy
+   ...
+   fun:je_malloc_tsd_boot0
+}
+
+# Setenv is known-leaking when overwriting mappings. This is triggered by re-initializing
+# ANDROID_DATA. Ignore all setenv leaks.
+{
+   SetenvAndroidDataReinit
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:malloc
+   fun:setenv
+}
+
+{
+   b/31275764
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:malloc
+   ...
+   fun:_ZN3art7Runtime17InitNativeMethodsEv
+}
+
+# art::MemMap::MapInternal() uses msync() to check for the existence of memory mappings.
+{
+  art::MemMap::MapInternal()
+  Memcheck:Param
+  msync(start)
+  fun:msync
+  fun:_ZN3art6MemMap11MapInternalEPvmiiilb
+}
+
+{
+   process_vm_readv
+   Memcheck:Param
+   process_vm_readv(lvec[...])
+   fun:process_vm_readv
+}
diff --git a/tools/art b/tools/art
index 781ee2f..1c603d4 100644
--- a/tools/art
+++ b/tools/art
@@ -77,6 +77,7 @@
 Supported OPTIONS include:
   --32                     Use the 32-bit Android Runtime.
   --64                     Use the 64-bit Android Runtime.
+  --callgrind              Launch the Android Runtime in callgrind.
   -d                       Use the debug ART library (libartd.so).
   --debug                  Equivalent to -d.
   --gdb                    Launch the Android Runtime in gdb.
@@ -268,6 +269,9 @@
   --64)
     ART_BINARY=dalvikvm64
     ;;
+  --callgrind)
+    LAUNCH_WRAPPER="valgrind --tool=callgrind"
+    ;;
   -d)
     ;& # Fallthrough
   --debug)