Merge "Update apex rules for dex2oatd"
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index b6d6600..e1b5b62 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -28,7 +28,7 @@
 #include "jni/java_vm_ext.h"
 #include "jni/jni_env_ext.h"
 #include "mirror/throwable.h"
-#include "nativehelper/ScopedLocalRef.h"
+#include "nativehelper/scoped_local_ref.h"
 #include "runtime-inl.h"
 #include "runtime_callbacks.h"
 #include "scoped_thread_state_change-inl.h"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index f00da9c..67d85c1 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -198,7 +198,7 @@
 ART_GTEST_oat_file_assistant_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
 ART_GTEST_dexoptanalyzer_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
 ART_GTEST_image_space_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
-ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex MainUncompressed MultiDexUncompressed
+ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex MainUncompressed MultiDexUncompressed MainStripped Nested MultiDexModifiedSecondary
 ART_GTEST_oat_test_DEX_DEPS := Main
 ART_GTEST_oat_writer_test_DEX_DEPS := Main
 ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
@@ -216,6 +216,7 @@
 ART_GTEST_verifier_deps_test_DEX_DEPS := VerifierDeps VerifierDepsMulti MultiDex
 ART_GTEST_dex_to_dex_decompiler_test_DEX_DEPS := VerifierDeps DexToDexDecompiler
 ART_GTEST_oatdump_app_test_DEX_DEPS := ProfileTestMultiDex
+ART_GTEST_oatdump_test_DEX_DEPS := ProfileTestMultiDex
 
 # The elf writer test has dependencies on core.oat.
 ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_DEFAULT_64) $(HOST_CORE_IMAGE_DEFAULT_32)
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index d35ceae..9b5c638 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -18,7 +18,6 @@
     "libopenjdkjvm",
     "libopenjdkjvmti",
     "libadbconnection",
-    "libjavacrypto",
 ]
 bionic_native_shared_libs = [
     "libc",
@@ -86,9 +85,13 @@
 art_tools_device_binaries = art_tools_common_binaries + art_tools_device_only_binaries
 art_tools_host_binaries = art_tools_common_binaries + art_tools_host_only_binaries
 
-// (Some) Libcore native libraries.
+// Libcore native libraries.
 libcore_native_shared_libs = [
+    "libjavacore",
     "libopenjdk",
+    "libexpat",
+    "libz",
+    "libziparchive"
 ]
 
 // Java libraries
diff --git a/build/apex/ld.config.txt b/build/apex/ld.config.txt
index d5eb9fa..d0145e4 100644
--- a/build/apex/ld.config.txt
+++ b/build/apex/ld.config.txt
@@ -8,7 +8,7 @@
 dir.runtime = /apex/com.android.runtime/bin/
 
 [runtime]
-additional.namespaces = platform,conscrypt
+additional.namespaces = platform,conscrypt,runtime
 
 # Keep in sync with the runtime namespace in /system/etc/ld.config.txt.
 namespace.default.isolated = true
@@ -54,3 +54,16 @@
 namespace.conscrypt.link.platform.shared_libs  = libc.so
 namespace.conscrypt.link.platform.shared_libs += libm.so
 namespace.conscrypt.link.platform.shared_libs += libdl.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace is an alias for the default namespace.
+###############################################################################
+namespace.runtime.isolated = true
+namespace.runtime.visible = true
+namespace.runtime.links = default
+namespace.runtime.link.default.allow_all_shared_libs = true
+namespace.runtime.links += platform
+# TODO(b/119867084): Restrict fallback to platform namespace to PALette library.
+namespace.runtime.link.platform.allow_all_shared_libs = true
diff --git a/build/apex/runtests.sh b/build/apex/runtests.sh
index 4c3eb0a..155709a 100755
--- a/build/apex/runtests.sh
+++ b/build/apex/runtests.sh
@@ -178,8 +178,12 @@
   check_library libopenjdkjvmti.so
   check_library libprofile.so
   # Check that the mounted image contains Android Core libraries.
+  check_library "libexpat${host_suffix}.so"
+  check_library libjavacore.so
   check_library libjavacrypto.so
   check_library libopenjdk.so
+  check_library "libz${host_suffix}.so"
+  check_library libziparchive.so
   # Check that the mounted image contains additional required libraries.
   check_library libadbconnection.so
 
@@ -275,7 +279,7 @@
   echo "$partition" | cmp "$image_filesystems" -
 
   # Mount the image from the Android Runtime APEX.
-  guestmount -a "$image_file" -m "$partition" "$mount_point"
+  guestmount -a "$image_file" -m "$partition" --ro "$mount_point"
 }
 
 # Testing release APEX package (com.android.runtime.release).
@@ -288,6 +292,7 @@
 
 work_dir=$(mktemp -d)
 mount_point="$work_dir/image"
+host_suffix=""
 
 trap finish_target EXIT
 
@@ -321,6 +326,7 @@
 
 work_dir=$(mktemp -d)
 mount_point="$work_dir/image"
+host_suffix=""
 
 trap finish_target EXIT
 
@@ -392,6 +398,7 @@
 
 work_dir=$(mktemp -d)
 mount_point="$work_dir/zip"
+host_suffix="-host"
 
 trap finish_host EXIT
 
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 8440e9a..96d6d2a 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1789,6 +1789,14 @@
     invoke_type = kVirtual;
   }
 
+  bool caller_dead_reference_safe = graph_->IsDeadReferenceSafe();
+  const dex::ClassDef& callee_class = resolved_method->GetClassDef();
+  // MethodContainsRSensitiveAccess is currently slow, but HasDeadReferenceSafeAnnotation()
+  // is currently rarely true.
+  bool callee_dead_reference_safe =
+      annotations::HasDeadReferenceSafeAnnotation(callee_dex_file, callee_class)
+      && !annotations::MethodContainsRSensitiveAccess(callee_dex_file, callee_class, method_index);
+
   const int32_t caller_instruction_counter = graph_->GetCurrentInstructionId();
   HGraph* callee_graph = new (graph_->GetAllocator()) HGraph(
       graph_->GetAllocator(),
@@ -1797,6 +1805,7 @@
       method_index,
       codegen_->GetCompilerOptions().GetInstructionSet(),
       invoke_type,
+      callee_dead_reference_safe,
       graph_->IsDebuggable(),
       /* osr= */ false,
       caller_instruction_counter);
@@ -2023,6 +2032,13 @@
     inline_stats_->AddTo(stats_);
   }
 
+  if (caller_dead_reference_safe && !callee_dead_reference_safe) {
+    // Caller was dead reference safe, but is not anymore, since we inlined dead
+    // reference unsafe code. Prior transformations remain valid, since they did not
+    // affect the inlined code.
+    graph_->MarkDeadReferenceUnsafe();
+  }
+
   return true;
 }
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 48fb611..c70674b 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -317,6 +317,7 @@
          uint32_t method_idx,
          InstructionSet instruction_set,
          InvokeType invoke_type = kInvalidInvokeType,
+         bool dead_reference_safe = false,
          bool debuggable = false,
          bool osr = false,
          int start_instruction_id = 0)
@@ -336,6 +337,7 @@
         has_simd_(false),
         has_loops_(false),
         has_irreducible_loops_(false),
+        dead_reference_safe_(dead_reference_safe),
         debuggable_(debuggable),
         current_instruction_id_(start_instruction_id),
         dex_file_(dex_file),
@@ -526,6 +528,12 @@
     has_bounds_checks_ = value;
   }
 
+  // Is the code known to be robust against eliminating dead references
+  // and the effects of early finalization?
+  bool IsDeadReferenceSafe() const { return dead_reference_safe_; }
+
+  void MarkDeadReferenceUnsafe() { dead_reference_safe_ = false; }
+
   bool IsDebuggable() const { return debuggable_; }
 
   // Returns a constant of the given type and value. If it does not exist
@@ -704,6 +712,14 @@
   // so there might be false positives.
   bool has_irreducible_loops_;
 
+  // Is the code known to be robust against eliminating dead references
+  // and the effects of early finalization? If false, dead reference variables
+  // are kept if they might be visible to the garbage collector.
+  // Currently this means that the class was declared to be dead-reference-safe,
+  // the method accesses no reachability-sensitive fields or data, and the same
+  // is true for any methods that were inlined into the current one.
+  bool dead_reference_safe_;
+
   // Indicates whether the graph should be compiled in a way that
   // ensures full debuggability. If false, we can apply more
   // aggressive optimizations that may limit the level of debugging.
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 42dbc77..e8f8d32 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -828,6 +828,29 @@
   }
 
   CodeItemDebugInfoAccessor code_item_accessor(dex_file, code_item, method_idx);
+
+  bool dead_reference_safe;
+  ArrayRef<const uint8_t> interpreter_metadata;
+  // For AOT compilation, we may not get a method, for example if its class is erroneous,
+  // possibly due to an unavailable superclass.  JIT should always have a method.
+  DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr);
+  if (method != nullptr) {
+    const dex::ClassDef* containing_class;
+    {
+      ScopedObjectAccess soa(Thread::Current());
+      containing_class = &method->GetClassDef();
+      interpreter_metadata = method->GetQuickenedInfo();
+    }
+    // MethodContainsRSensitiveAccess is currently slow, but HasDeadReferenceSafeAnnotation()
+    // is currently rarely true.
+    dead_reference_safe =
+        annotations::HasDeadReferenceSafeAnnotation(dex_file, *containing_class)
+        && !annotations::MethodContainsRSensitiveAccess(dex_file, *containing_class, method_idx);
+  } else {
+    // If we could not resolve the class, conservatively assume it's dead-reference unsafe.
+    dead_reference_safe = false;
+  }
+
   HGraph* graph = new (allocator) HGraph(
       allocator,
       arena_stack,
@@ -835,17 +858,12 @@
       method_idx,
       compiler_options.GetInstructionSet(),
       kInvalidInvokeType,
+      dead_reference_safe,
       compiler_driver->GetCompilerOptions().GetDebuggable(),
-      osr);
+      /* osr= */ osr);
 
-  ArrayRef<const uint8_t> interpreter_metadata;
-  // For AOT compilation, we may not get a method, for example if its class is erroneous.
-  // JIT should always have a method.
-  DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr);
   if (method != nullptr) {
     graph->SetArtMethod(method);
-    ScopedObjectAccess soa(Thread::Current());
-    interpreter_metadata = method->GetQuickenedInfo();
   }
 
   std::unique_ptr<CodeGenerator> codegen(
@@ -963,6 +981,7 @@
       method_idx,
       compiler_options.GetInstructionSet(),
       kInvalidInvokeType,
+      /* dead_reference_safe= */ true,  // Intrinsics don't affect dead reference safety.
       compiler_options.GetDebuggable(),
       /* osr= */ false);
 
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 92d0b08..c883907 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -1155,10 +1155,11 @@
  *
  * (a) Non-environment uses of an instruction always make
  *     the instruction live.
- * (b) Environment uses of an instruction whose type is
- *     object (that is, non-primitive), make the instruction live.
- *     This is due to having to keep alive objects that have
- *     finalizers deleting native objects.
+ * (b) Environment uses of an instruction whose type is object (that is, non-primitive), make the
+ *     instruction live, unless the class has an @DeadReferenceSafe annotation.
+ *     This avoids unexpected premature reference enqueuing or finalization, which could
+ *     result in premature deletion of native objects.  In the presence of @DeadReferenceSafe,
+ *     object references are treated like primitive types.
  * (c) When the graph has the debuggable property, environment uses
  *     of an instruction that has a primitive type make the instruction live.
  *     If the graph does not have the debuggable property, the environment
@@ -1287,6 +1288,7 @@
     // When compiling in OSR mode, all loops in the compiled method may be entered
     // from the interpreter via SuspendCheck; thus we need to preserve the environment.
     if (env_holder->IsSuspendCheck() && graph->IsCompilingOsr()) return true;
+    if (graph -> IsDeadReferenceSafe()) return false;
     return instruction->GetType() == DataType::Type::kReference;
   }
 
diff --git a/libdexfile/dex/dex_instruction.cc b/libdexfile/dex/dex_instruction.cc
index 83663c5..f36a2aa 100644
--- a/libdexfile/dex/dex_instruction.cc
+++ b/libdexfile/dex/dex_instruction.cc
@@ -402,9 +402,9 @@
         case INVOKE_VIRTUAL_QUICK:
           if (file != nullptr) {
             os << opcode << " {";
-            uint32_t method_idx = VRegB_35c();
+            uint32_t vtable_offset = VRegB_35c();
             DumpArgs(VRegA_35c());
-            os << "},  // vtable@" << method_idx;
+            os << "},  // vtable@" << vtable_offset;
             break;
           }
           FALLTHROUGH_INTENDED;
diff --git a/oatdump/oatdump_image_test.cc b/oatdump/oatdump_image_test.cc
index de48b04..0a076f0 100644
--- a/oatdump/oatdump_image_test.cc
+++ b/oatdump/oatdump_image_test.cc
@@ -40,13 +40,13 @@
 TEST_F(OatDumpTest, TestOatImage) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kDynamic, kModeOat, {}, kListAndCode));
+  ASSERT_TRUE(Exec(kDynamic, kModeCoreOat, {}, kListAndCode));
 }
 TEST_F(OatDumpTest, TestOatImageStatic) {
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
-  ASSERT_TRUE(Exec(kStatic, kModeOat, {}, kListAndCode));
+  ASSERT_TRUE(Exec(kStatic, kModeCoreOat, {}, kListAndCode));
 }
 
 }  // namespace art
diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc
index e6936f6..7b1de01 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <android-base/file.h>
+
 #include "oatdump_test.h"
 
 namespace art {
@@ -90,8 +92,11 @@
   // Test is failing on target, b/77469384.
   TEST_DISABLED_FOR_TARGET();
   std::string error_msg;
+  ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {}));
   ASSERT_TRUE(Exec(kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
-  const std::string dex_location = tmp_dir_+ "/core-oj-hostdex.jar_export.dex";
+  const std::string dex_location =
+      tmp_dir_+ "/" + android::base::Basename(GetTestDexFileName(GetAppBaseName().c_str())) +
+      "_export.dex";
   const std::string dexdump2 = GetExecutableFilePath("dexdump2",
                                                      /*is_debug=*/false,
                                                      /*is_static=*/false);
@@ -104,6 +109,7 @@
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
+  ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {}));
   ASSERT_TRUE(Exec(kStatic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
 }
 
diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h
index dfa659b..3ead8de 100644
--- a/oatdump/oatdump_test.h
+++ b/oatdump/oatdump_test.h
@@ -90,6 +90,7 @@
 
   enum Mode {
     kModeOat,
+    kModeCoreOat,
     kModeOatWithBootImage,
     kModeArt,
     kModeSymbolize,
@@ -199,9 +200,11 @@
         exec_argv.push_back("--instruction-set=" + std::string(
             GetInstructionSetString(kRuntimeISA)));
         exec_argv.push_back("--oat-file=" + GetAppOdexName());
+      } else if (mode == kModeCoreOat) {
+        exec_argv.push_back("--oat-file=" + core_oat_location_);
       } else {
         CHECK_EQ(static_cast<size_t>(mode), static_cast<size_t>(kModeOat));
-        exec_argv.push_back("--oat-file=" + core_oat_location_);
+        exec_argv.push_back("--oat-file=" + GetAppOdexName());
       }
     }
     exec_argv.insert(exec_argv.end(), args.begin(), args.end());
diff --git a/runtime/Android.bp b/runtime/Android.bp
index b89eb02..a3081e9 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -396,8 +396,10 @@
         "libnativeloader",
         "libbacktrace",
         "liblog",
-        // For atrace, properties, ashmem, set_sched_policy.
+        // For atrace, properties, ashmem.
         "libcutils",
+        // For set_sched_policy.
+        "libprocessgroup",
         // For common macros.
         "libbase",
     ],
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 07193b2..44b80df 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -547,11 +547,10 @@
 ArrayRef<const uint8_t> ArtMethod::GetQuickenedInfo() {
   const DexFile& dex_file = *GetDexFile();
   const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
-  if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) {
+  if (oat_dex_file == nullptr) {
     return ArrayRef<const uint8_t>();
   }
-  return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(dex_file,
-                                                                       GetDexMethodIndex());
+  return oat_dex_file->GetQuickenedInfoOf(dex_file, GetDexMethodIndex());
 }
 
 uint16_t ArtMethod::GetIndexFromQuickening(uint32_t dex_pc) {
diff --git a/runtime/base/locks.h b/runtime/base/locks.h
index 57719f1..b7d8e31 100644
--- a/runtime/base/locks.h
+++ b/runtime/base/locks.h
@@ -71,6 +71,7 @@
   kRosAllocGlobalLock,
   kRosAllocBracketLock,
   kRosAllocBulkFreeLock,
+  kAllocSpaceLock,
   kTaggingLockLevel,
   kTransactionLogLock,
   kCustomTlsLock,
@@ -84,7 +85,6 @@
   kReferenceQueueClearedReferencesLock,
   kReferenceProcessorLock,
   kJitDebugInterfaceLock,
-  kAllocSpaceLock,
   kBumpPointerSpaceBlockLock,
   kArenaPoolLock,
   kInternTableLock,
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index e75baf8..050be4a 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -26,6 +26,7 @@
 #include "class_linker-inl.h"
 #include "class_root.h"
 #include "dex/dex_file-inl.h"
+#include "dex/dex_instruction-inl.h"
 #include "jni/jni_internal.h"
 #include "jvalue-inl.h"
 #include "mirror/array-alloc-inl.h"
@@ -36,6 +37,7 @@
 #include "mirror/object_array-inl.h"
 #include "oat_file.h"
 #include "obj_ptr-inl.h"
+#include "quicken_info.h"
 #include "reflection.h"
 #include "thread.h"
 #include "well_known_classes.h"
@@ -146,32 +148,36 @@
   return actual == expected;
 }
 
-const AnnotationSetItem* FindAnnotationSetForField(ArtField* field)
+static const AnnotationSetItem* FindAnnotationSetForField(const DexFile& dex_file,
+                                                          const dex::ClassDef& class_def,
+                                                          uint32_t field_index)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile* dex_file = field->GetDexFile();
+  const AnnotationsDirectoryItem* annotations_dir = dex_file.GetAnnotationsDirectory(class_def);
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  const FieldAnnotationsItem* field_annotations = dex_file.GetFieldAnnotations(annotations_dir);
+  if (field_annotations == nullptr) {
+    return nullptr;
+  }
+  uint32_t field_count = annotations_dir->fields_size_;
+  for (uint32_t i = 0; i < field_count; ++i) {
+    if (field_annotations[i].field_idx_ == field_index) {
+      return dex_file.GetFieldAnnotationSetItem(field_annotations[i]);
+    }
+  }
+  return nullptr;
+}
+
+static const AnnotationSetItem* FindAnnotationSetForField(ArtField* field)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
   ObjPtr<mirror::Class> klass = field->GetDeclaringClass();
   const dex::ClassDef* class_def = klass->GetClassDef();
   if (class_def == nullptr) {
     DCHECK(klass->IsProxyClass());
     return nullptr;
   }
-  const AnnotationsDirectoryItem* annotations_dir = dex_file->GetAnnotationsDirectory(*class_def);
-  if (annotations_dir == nullptr) {
-    return nullptr;
-  }
-  const FieldAnnotationsItem* field_annotations =
-      dex_file->GetFieldAnnotations(annotations_dir);
-  if (field_annotations == nullptr) {
-    return nullptr;
-  }
-  uint32_t field_index = field->GetDexFieldIndex();
-  uint32_t field_count = annotations_dir->fields_size_;
-  for (uint32_t i = 0; i < field_count; ++i) {
-    if (field_annotations[i].field_idx_ == field_index) {
-      return dex_file->GetFieldAnnotationSetItem(field_annotations[i]);
-    }
-  }
-  return nullptr;
+  return FindAnnotationSetForField(*field->GetDexFile(), *class_def, field->GetDexFieldIndex());
 }
 
 const AnnotationItem* SearchAnnotationSet(const DexFile& dex_file,
@@ -276,9 +282,9 @@
   return nullptr;
 }
 
-const AnnotationSetItem* FindAnnotationSetForMethod(const DexFile& dex_file,
-                                                    const dex::ClassDef& class_def,
-                                                    uint32_t method_index) {
+static const AnnotationSetItem* FindAnnotationSetForMethod(const DexFile& dex_file,
+                                                           const dex::ClassDef& class_def,
+                                                           uint32_t method_index) {
   const AnnotationsDirectoryItem* annotations_dir = dex_file.GetAnnotationsDirectory(class_def);
   if (annotations_dir == nullptr) {
     return nullptr;
@@ -329,7 +335,7 @@
   return nullptr;
 }
 
-const AnnotationSetItem* FindAnnotationSetForClass(const ClassData& klass)
+static const AnnotationSetItem* FindAnnotationSetForClass(const ClassData& klass)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const DexFile& dex_file = klass.GetDexFile();
   const dex::ClassDef* class_def = klass.GetClassDef();
@@ -1310,6 +1316,191 @@
   return access_flags;
 }
 
+bool FieldIsReachabilitySensitive(const DexFile& dex_file,
+                                  const dex::ClassDef& class_def,
+                                  uint32_t field_index)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const AnnotationSetItem* annotation_set =
+      FindAnnotationSetForField(dex_file, class_def, field_index);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  const AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set,
+      "Ldalvik/annotation/optimization/ReachabilitySensitive;", DexFile::kDexVisibilityRuntime);
+  // TODO: We're missing the equivalent of DCheckNativeAnnotation (not a DCHECK). Does it matter?
+  return annotation_item != nullptr;
+}
+
+bool MethodIsReachabilitySensitive(const DexFile& dex_file,
+                                   const dex::ClassDef& class_def,
+                                   uint32_t method_index)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const AnnotationSetItem* annotation_set =
+      FindAnnotationSetForMethod(dex_file, class_def, method_index);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  const AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set,
+      "Ldalvik/annotation/optimization/ReachabilitySensitive;", DexFile::kDexVisibilityRuntime);
+  return annotation_item != nullptr;
+}
+
+static bool MethodIsReachabilitySensitive(const DexFile& dex_file,
+                                               uint32_t method_index)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  DCHECK(method_index < dex_file.NumMethodIds());
+  const dex::MethodId& method_id = dex_file.GetMethodId(method_index);
+  dex::TypeIndex class_index = method_id.class_idx_;
+  const dex::ClassDef * class_def = dex_file.FindClassDef(class_index);
+  return class_def != nullptr
+         && MethodIsReachabilitySensitive(dex_file, *class_def, method_index);
+}
+
+bool MethodContainsRSensitiveAccess(const DexFile& dex_file,
+                                    const dex::ClassDef& class_def,
+                                    uint32_t method_index)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  // TODO: This is too slow to run very regularly. Currently this is only invoked in the
+  // presence of @DeadReferenceSafe, which will be rare. In the long run, we need to quickly
+  // check once whether a class has any @ReachabilitySensitive annotations. If not, we can
+  // immediately return false here for any method in that class.
+  uint32_t code_item_offset = dex_file.FindCodeItemOffset(class_def, method_index);
+  const dex::CodeItem* code_item = dex_file.GetCodeItem(code_item_offset);
+  CodeItemInstructionAccessor accessor(dex_file, code_item);
+  if (!accessor.HasCodeItem()) {
+    return false;
+  }
+  ArrayRef<const uint8_t> quicken_data;
+  const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
+  if (oat_dex_file != nullptr) {
+    quicken_data = oat_dex_file->GetQuickenedInfoOf(dex_file, method_index);
+  }
+  const QuickenInfoTable quicken_info(quicken_data);
+  uint32_t quicken_index = 0;
+  for (DexInstructionIterator iter = accessor.begin(); iter != accessor.end(); ++iter) {
+    switch (iter->Opcode()) {
+      case Instruction::IGET:
+      case Instruction::IGET_QUICK:
+      case Instruction::IGET_WIDE:
+      case Instruction::IGET_WIDE_QUICK:
+      case Instruction::IGET_OBJECT:
+      case Instruction::IGET_OBJECT_QUICK:
+      case Instruction::IGET_BOOLEAN:
+      case Instruction::IGET_BOOLEAN_QUICK:
+      case Instruction::IGET_BYTE:
+      case Instruction::IGET_BYTE_QUICK:
+      case Instruction::IGET_CHAR:
+      case Instruction::IGET_CHAR_QUICK:
+      case Instruction::IGET_SHORT:
+      case Instruction::IGET_SHORT_QUICK:
+      case Instruction::IPUT:
+      case Instruction::IPUT_QUICK:
+      case Instruction::IPUT_WIDE:
+      case Instruction::IPUT_WIDE_QUICK:
+      case Instruction::IPUT_OBJECT:
+      case Instruction::IPUT_OBJECT_QUICK:
+      case Instruction::IPUT_BOOLEAN:
+      case Instruction::IPUT_BOOLEAN_QUICK:
+      case Instruction::IPUT_BYTE:
+      case Instruction::IPUT_BYTE_QUICK:
+      case Instruction::IPUT_CHAR:
+      case Instruction::IPUT_CHAR_QUICK:
+      case Instruction::IPUT_SHORT:
+      case Instruction::IPUT_SHORT_QUICK:
+        {
+          uint32_t field_index;
+          if (iter->IsQuickened()) {
+            field_index = quicken_info.GetData(quicken_index);
+          } else {
+            field_index = iter->VRegC_22c();
+          }
+          DCHECK(field_index < dex_file.NumFieldIds());
+          // We only guarantee to pay attention to the annotation if it's in the same class,
+          // or a containing class, but it's OK to do so in other cases.
+          const dex::FieldId& field_id = dex_file.GetFieldId(field_index);
+          dex::TypeIndex class_index = field_id.class_idx_;
+          const dex::ClassDef * field_class_def = dex_file.FindClassDef(class_index);
+          // We do not handle the case in which the field is declared in a superclass, and
+          // don't claim to do so. The annotated field should normally be private.
+          if (field_class_def != nullptr
+              && FieldIsReachabilitySensitive(dex_file, *field_class_def, field_index)) {
+            return true;
+          }
+        }
+        break;
+      case Instruction::INVOKE_SUPER:
+        // Cannot call method in same class. TODO: Try an explicit superclass lookup for
+        // better "best effort"?
+        break;
+      case Instruction::INVOKE_INTERFACE:
+        // We handle an interface call just like a virtual call. We will find annotations
+        // on interface methods/fields visible to us, but not of the annotation is in a
+        // super-interface. Again, we could just ignore it.
+      case Instruction::INVOKE_VIRTUAL:
+      case Instruction::INVOKE_DIRECT:
+        {
+          uint32_t called_method_index = iter->VRegB_35c();
+          if (MethodIsReachabilitySensitive(dex_file, called_method_index)) {
+            return true;
+          }
+        }
+        break;
+      case Instruction::INVOKE_INTERFACE_RANGE:
+      case Instruction::INVOKE_VIRTUAL_RANGE:
+      case Instruction::INVOKE_DIRECT_RANGE:
+        {
+          uint32_t called_method_index = iter->VRegB_3rc();
+          if (MethodIsReachabilitySensitive(dex_file, called_method_index)) {
+            return true;
+          }
+        }
+        break;
+      case Instruction::INVOKE_VIRTUAL_QUICK:
+      case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
+        {
+          uint32_t called_method_index = quicken_info.GetData(quicken_index);
+          if (MethodIsReachabilitySensitive(dex_file, called_method_index)) {
+            return true;
+          }
+        }
+        break;
+        // We explicitly do not handle indirect ReachabilitySensitive accesses through VarHandles,
+        // etc. Thus we ignore INVOKE_CUSTOM / INVOKE_CUSTOM_RANGE / INVOKE_POLYMORPHIC /
+        // INVOKE_POLYMORPHIC_RANGE.
+      default:
+        // There is no way to add an annotation to array elements, and so far we've encountered no
+        // need for that, so we ignore AGET and APUT.
+        // It's impractical or impossible to garbage collect a class while one of its methods is
+        // on the call stack. We allow ReachabilitySensitive annotations on static methods and
+        // fields, but they can be safely ignored.
+        break;
+    }
+    if (QuickenInfoTable::NeedsIndexForInstruction(&iter.Inst())) {
+      ++quicken_index;
+    }
+  }
+  return false;
+}
+
+bool HasDeadReferenceSafeAnnotation(const DexFile& dex_file,
+                                    const dex::ClassDef& class_def)
+  // TODO: This should check outer classes as well.
+  // It's conservatively correct not to do so.
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const AnnotationsDirectoryItem* annotations_dir =
+      dex_file.GetAnnotationsDirectory(class_def);
+  if (annotations_dir == nullptr) {
+    return false;
+  }
+  const AnnotationSetItem* annotation_set = dex_file.GetClassAnnotationSet(annotations_dir);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  const AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set,
+      "Ldalvik/annotation/optimization/DeadReferenceSafe;", DexFile::kDexVisibilityRuntime);
+  return annotation_item != nullptr;
+}
+
 ObjPtr<mirror::Object> GetAnnotationForClass(Handle<mirror::Class> klass,
                                              Handle<mirror::Class> annotation_class) {
   ClassData data(klass);
diff --git a/runtime/dex/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h
index 3625cee..018e87f 100644
--- a/runtime/dex/dex_file_annotations.h
+++ b/runtime/dex/dex_file_annotations.h
@@ -78,6 +78,7 @@
                                Handle<mirror::Class> annotation_class,
                                uint32_t visibility = DexFile::kDexVisibilityRuntime)
     REQUIRES_SHARED(Locks::mutator_lock_);
+
 // Check whether a method from the `dex_file` with the given `method_index`
 // is annotated with @dalvik.annotation.optimization.FastNative or
 // @dalvik.annotation.optimization.CriticalNative with build visibility.
@@ -85,6 +86,28 @@
 uint32_t GetNativeMethodAnnotationAccessFlags(const DexFile& dex_file,
                                               const dex::ClassDef& class_def,
                                               uint32_t method_index);
+// Is the field from the `dex_file` with the given `field_index`
+// annotated with @dalvik.annotation.optimization.ReachabilitySensitive?
+bool FieldIsReachabilitySensitive(const DexFile& dex_file,
+                                  const dex::ClassDef& class_def,
+                                  uint32_t field_index);
+// Is the method from the `dex_file` with the given `method_index`
+// annotated with @dalvik.annotation.optimization.ReachabilitySensitive?
+bool MethodIsReachabilitySensitive(const DexFile& dex_file,
+                                   const dex::ClassDef& class_def,
+                                   uint32_t method_index);
+// Does the method from the `dex_file` with the given `method_index` contain an access to a field
+// annotated with @dalvik.annotation.optimization.ReachabilitySensitive, or a call to a method
+// with that annotation?
+// Class_def is the class defining the method. We consider only accessses to classes or methods
+// declared in the static type of the corresponding object. We may overlook accesses to annotated
+// fields or methods that are in neither class_def nor a containing (outer) class.
+bool MethodContainsRSensitiveAccess(const DexFile& dex_file,
+                                    const dex::ClassDef& class_def,
+                                    uint32_t method_index);
+// Is the given class annotated with @dalvik.annotation.optimization.DeadReferenceSafe?
+bool HasDeadReferenceSafeAnnotation(const DexFile& dex_file,
+                                    const dex::ClassDef& class_def);
 
 // Class annotations.
 ObjPtr<mirror::Object> GetAnnotationForClass(Handle<mirror::Class> klass,
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5f62d75..8020f86 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2878,6 +2878,15 @@
   DCHECK_GE(now, last_update_time_gc_count_rate_histograms_);
   uint64_t time_since_last_update = now - last_update_time_gc_count_rate_histograms_;
   uint64_t num_of_windows = time_since_last_update / kGcCountRateHistogramWindowDuration;
+
+  // The computed number of windows can be incoherently high if NanoTime() is not monotonic.
+  // Setting a limit on its maximum value reduces the impact on CPU time in such cases.
+  if (num_of_windows > kGcCountRateHistogramMaxNumMissedWindows) {
+    LOG(WARNING) << "Reducing the number of considered missed Gc histogram windows from "
+                 << num_of_windows << " to " << kGcCountRateHistogramMaxNumMissedWindows;
+    num_of_windows = kGcCountRateHistogramMaxNumMissedWindows;
+  }
+
   if (time_since_last_update >= kGcCountRateHistogramWindowDuration) {
     // Record the first window.
     gc_count_rate_histogram_.AddValue(gc_count_last_window_ - 1);  // Exclude the current run.
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 4c5d896..6bdba12 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -1495,6 +1495,8 @@
   uint64_t blocking_gc_time_;
   // The duration of the window for the GC count rate histograms.
   static constexpr uint64_t kGcCountRateHistogramWindowDuration = MsToNs(10 * 1000);  // 10s.
+  // Maximum number of missed histogram windows for which statistics will be collected.
+  static constexpr uint64_t kGcCountRateHistogramMaxNumMissedWindows = 100;
   // The last time when the GC count rate histograms were updated.
   // This is rounded by kGcCountRateHistogramWindowDuration (a multiple of 10s).
   uint64_t last_update_time_gc_count_rate_histograms_;
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 841ace5..f908c62 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -438,6 +438,7 @@
       const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
       const MethodReferenceCollection::IndexVector& indices = pair.second;
       VLOG(profiler) << "Location " << dex_file->GetLocation()
+                     << " base_location=" << base_location
                      << " found=" << (locations.find(base_location) != locations.end())
                      << " indices size=" << indices.size();
       if (locations.find(base_location) != locations.end()) {
@@ -799,11 +800,38 @@
 static void AddTrackedLocationsToMap(const std::string& output_filename,
                                      const std::vector<std::string>& code_paths,
                                      SafeMap<std::string, std::set<std::string>>* map) {
+  std::vector<std::string> code_paths_and_filenames;
+  // The dex locations are sometimes set to the filename instead of the full path.
+  // So make sure we have both "locations" when tracking what needs to be profiled.
+  //   - apps + system server have filenames
+  //   - boot classpath elements have full paths
+
+  // TODO(calin, ngeoffray, vmarko) This is an workaround for using filanames as
+  // dex locations - needed to prebuilt with a partial boot image
+  // (commit: c4a924d8c74241057d957d360bf31cd5cd0e4f9c).
+  // We should find a better way which allows us to do the tracking based on full paths.
+  for (const std::string& path : code_paths) {
+    size_t last_sep_index = path.find_last_of('/');
+    if (last_sep_index == path.size() - 1) {
+      // Should not happen, but anyone can register code paths so better be prepared and ignore
+      // such locations.
+      continue;
+    }
+    std::string filename = last_sep_index == std::string::npos
+        ? path
+        : path.substr(last_sep_index + 1);
+
+    code_paths_and_filenames.push_back(path);
+    code_paths_and_filenames.push_back(filename);
+  }
+
   auto it = map->find(output_filename);
   if (it == map->end()) {
-    map->Put(output_filename, std::set<std::string>(code_paths.begin(), code_paths.end()));
+    map->Put(
+        output_filename,
+        std::set<std::string>(code_paths_and_filenames.begin(), code_paths_and_filenames.end()));
   } else {
-    it->second.insert(code_paths.begin(), code_paths.end());
+    it->second.insert(code_paths_and_filenames.begin(), code_paths_and_filenames.end());
   }
 }
 
diff --git a/runtime/jni/java_vm_ext_test.cc b/runtime/jni/java_vm_ext_test.cc
index dfe50cf..4a7b1ca 100644
--- a/runtime/jni/java_vm_ext_test.cc
+++ b/runtime/jni/java_vm_ext_test.cc
@@ -109,6 +109,7 @@
 }
 
 TEST_F(JavaVmExtTest, AttachCurrentThread_SmallStack) {
+  TEST_DISABLED_FOR_MEMORY_TOOL();  // b/123500163
   pthread_t pthread;
   pthread_attr_t attr;
   const char* reason = __PRETTY_FUNCTION__;
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index f4a8c50..d179b80 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1410,20 +1410,23 @@
 
 std::string OatFile::ResolveRelativeEncodedDexLocation(
       const char* abs_dex_location, const std::string& rel_dex_location) {
-  // For host, we still do resolution as the rel_dex_location might be absolute
-  // for a target dex (for example /system/foo/foo.apk).
-  if (abs_dex_location != nullptr && (rel_dex_location[0] != '/' || !kIsTargetBuild)) {
-    // Strip :classes<N>.dex used for secondary multidex files.
+  if (abs_dex_location != nullptr) {
     std::string base = DexFileLoader::GetBaseLocation(rel_dex_location);
+    // Strip :classes<N>.dex used for secondary multidex files.
     std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(rel_dex_location);
-
-    // Check if the base is a suffix of the provided abs_dex_location.
-    std::string target_suffix = ((rel_dex_location[0] != '/') ? "/" : "") + base;
-    std::string abs_location(abs_dex_location);
-    if (abs_location.size() > target_suffix.size()) {
-      size_t pos = abs_location.size() - target_suffix.size();
-      if (abs_location.compare(pos, std::string::npos, target_suffix) == 0) {
-        return abs_location + multidex_suffix;
+    if (!kIsTargetBuild) {
+      // For host, we still do resolution as the rel_dex_location might be absolute
+      // for a target dex (for example /system/foo/foo.apk).
+      return std::string(abs_dex_location) + multidex_suffix;
+    } else if (rel_dex_location[0] != '/') {
+      // Check if the base is a suffix of the provided abs_dex_location.
+      std::string target_suffix = ((rel_dex_location[0] != '/') ? "/" : "") + base;
+      std::string abs_location(abs_dex_location);
+      if (abs_location.size() > target_suffix.size()) {
+        size_t pos = abs_location.size() - target_suffix.size();
+        if (abs_location.compare(pos, std::string::npos, target_suffix) == 0) {
+          return abs_location + multidex_suffix;
+        }
       }
     }
   }
@@ -1833,6 +1836,16 @@
                            reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
 }
 
+ArrayRef<const uint8_t> OatDexFile::GetQuickenedInfoOf(const DexFile& dex_file,
+                                                       uint32_t dex_method_idx) const {
+  const OatFile* oat_file = GetOatFile();
+  if (oat_file == nullptr) {
+    return ArrayRef<const uint8_t>();
+  } else  {
+    return oat_file->GetVdexFile()->GetQuickenedInfoOf(dex_file, dex_method_idx);
+  }
+}
+
 const dex::ClassDef* OatDexFile::FindClassDef(const DexFile& dex_file,
                                               const char* descriptor,
                                               size_t hash) {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 3e9c01f..1ba6e49 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -502,6 +502,9 @@
     return dex_file_pointer_;
   }
 
+  ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file,
+                                             uint32_t dex_method_idx) const;
+
   // Looks up a class definition by its class descriptor. Hash must be
   // ComputeModifiedUtf8Hash(descriptor).
   static const dex::ClassDef* FindClassDef(const DexFile& dex_file,
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
index b547113..ce09da4d 100644
--- a/runtime/oat_file_test.cc
+++ b/runtime/oat_file_test.cc
@@ -35,10 +35,6 @@
       OatFile::ResolveRelativeEncodedDexLocation(
         nullptr, "/data/app/foo/base.apk"));
 
-  EXPECT_EQ(std::string("/system/framework/base.apk"),
-      OatFile::ResolveRelativeEncodedDexLocation(
-        "/data/app/foo/base.apk", "/system/framework/base.apk"));
-
   EXPECT_EQ(std::string("/data/app/foo/base.apk"),
       OatFile::ResolveRelativeEncodedDexLocation(
         "/data/app/foo/base.apk", "base.apk"));
@@ -55,13 +51,29 @@
       OatFile::ResolveRelativeEncodedDexLocation(
         "/data/app/foo/base.apk", "base.apk!classes11.dex"));
 
-  EXPECT_EQ(std::string("base.apk"),
-      OatFile::ResolveRelativeEncodedDexLocation(
-        "/data/app/foo/sludge.apk", "base.apk"));
-
-  EXPECT_EQ(std::string("o/base.apk"),
-      OatFile::ResolveRelativeEncodedDexLocation(
-        "/data/app/foo/base.apk", "o/base.apk"));
+  // Host and target differ in their way of handling locations
+  // that are prefix of one another, due to boot image files.
+  if (kIsTargetBuild) {
+    EXPECT_EQ(std::string("/system/framework/base.apk"),
+        OatFile::ResolveRelativeEncodedDexLocation(
+          "/data/app/foo/base.apk", "/system/framework/base.apk"));
+    EXPECT_EQ(std::string("base.apk"),
+        OatFile::ResolveRelativeEncodedDexLocation(
+          "/data/app/foo/sludge.apk", "base.apk"));
+    EXPECT_EQ(std::string("o/base.apk"),
+        OatFile::ResolveRelativeEncodedDexLocation(
+          "/data/app/foo/base.apk", "o/base.apk"));
+  } else {
+    EXPECT_EQ(std::string("/data/app/foo/base.apk"),
+        OatFile::ResolveRelativeEncodedDexLocation(
+          "/data/app/foo/base.apk", "/system/framework/base.apk"));
+    EXPECT_EQ(std::string("/data/app/foo/sludge.apk"),
+        OatFile::ResolveRelativeEncodedDexLocation(
+          "/data/app/foo/sludge.apk", "base.apk"));
+    EXPECT_EQ(std::string("/data/app/foo/base.apk"),
+        OatFile::ResolveRelativeEncodedDexLocation(
+          "/data/app/foo/base.apk", "o/base.apk"));
+  }
 }
 
 TEST_F(OatFileTest, LoadOat) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index a86bc94..feade83 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1752,7 +1752,8 @@
   // libcore can't because it's the library that implements System.loadLibrary!
   {
     std::string error_msg;
-    if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr, nullptr, &error_msg)) {
+    if (!java_vm_->LoadNativeLibrary(
+          env, "libjavacore.so", nullptr, WellKnownClasses::java_lang_Object, &error_msg)) {
       LOG(FATAL) << "LoadNativeLibrary failed for \"libjavacore.so\": " << error_msg;
     }
   }
@@ -1761,7 +1762,8 @@
                                                 ? "libopenjdkd.so"
                                                 : "libopenjdk.so";
     std::string error_msg;
-    if (!java_vm_->LoadNativeLibrary(env, kOpenJdkLibrary, nullptr, nullptr, &error_msg)) {
+    if (!java_vm_->LoadNativeLibrary(
+          env, kOpenJdkLibrary, nullptr, WellKnownClasses::java_lang_Object, &error_msg)) {
       LOG(FATAL) << "LoadNativeLibrary failed for \"" << kOpenJdkLibrary << "\": " << error_msg;
     }
   }
diff --git a/runtime/thread_android.cc b/runtime/thread_android.cc
index 8ff6c52..24864f9 100644
--- a/runtime/thread_android.cc
+++ b/runtime/thread_android.cc
@@ -21,7 +21,7 @@
 #include <sys/resource.h>
 #include <sys/time.h>
 
-#include <cutils/sched_policy.h>
+#include <processgroup/sched_policy.h>
 #include <utils/threads.h>
 
 #include "base/macros.h"
diff --git a/test/1339-dead-reference-safe/check b/test/1339-dead-reference-safe/check
new file mode 100644
index 0000000..795cfac
--- /dev/null
+++ b/test/1339-dead-reference-safe/check
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 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.
+
+# DeadReferenceSafe result differs for interpreted mode. A real failure
+# will produce an extra line anyway.
+
+diff --ignore-matching-lines="DeadReferenceSafe count:" -q $1 $2
diff --git a/test/1339-dead-reference-safe/expected.txt b/test/1339-dead-reference-safe/expected.txt
new file mode 100644
index 0000000..abafce4
--- /dev/null
+++ b/test/1339-dead-reference-safe/expected.txt
@@ -0,0 +1,6 @@
+JNI_OnLoad called
+DeadReferenceUnsafe count: 5
+DeadReferenceSafe count: N
+ReachabilitySensitive count: 5
+ReachabilitySensitiveFun count: 5
+ReachabilityFence count: 5
diff --git a/test/1339-dead-reference-safe/info.txt b/test/1339-dead-reference-safe/info.txt
new file mode 100644
index 0000000..b6ad217
--- /dev/null
+++ b/test/1339-dead-reference-safe/info.txt
@@ -0,0 +1 @@
+Test that @DeadReferenceSafe and @ReachabilitySensitive have the intended effect.
diff --git a/test/1339-dead-reference-safe/src/DeadReferenceSafeTest.java b/test/1339-dead-reference-safe/src/DeadReferenceSafeTest.java
new file mode 100644
index 0000000..0c19084
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/DeadReferenceSafeTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import dalvik.annotation.optimization.DeadReferenceSafe;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@DeadReferenceSafe
+public final class DeadReferenceSafeTest {
+  static AtomicInteger nFinalized = new AtomicInteger(0);
+  private static final int INNER_ITERS = 10;
+  static int count;
+  static boolean interpreted;
+  int n = 1;
+
+  private static void $noinline$loop() {
+    DeadReferenceSafeTest x;
+    // The loop allocates INNER_ITERS DeadReferenceSafeTest objects.
+    for (int i = 0; i < INNER_ITERS; ++i) {
+      // We've allocated i objects so far.
+      x = new DeadReferenceSafeTest();
+      count += x.n;
+      // x is dead here.
+      if (i == 5) {
+        // With dead reference elimination, all 6 objects should have been finalized here.
+        // However the interpreter doesn't (yet?) play by the proper rules.
+        Main.$noinline$gcAndCheck(nFinalized, (interpreted ? 5 : 6), "DeadReferenceSafe",
+            "Failed to reclaim dead reference in @DeadReferenceSafe code!");
+      }
+    }
+  }
+
+  private static void reset(int expected_count) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    if (nFinalized.get() != expected_count) {
+      System.out.println("DeadReferenceSafeTest: Wrong number of finalized objects:"
+                         + nFinalized.get());
+    }
+    nFinalized.set(0);
+  }
+
+  protected void finalize() {
+    nFinalized.incrementAndGet();
+  }
+
+  public static void runTest() {
+    try {
+      interpreted = !Main.ensureCompiled(DeadReferenceSafeTest.class, "$noinline$loop");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Unexpectedly threw " + e);
+    }
+
+    $noinline$loop();
+
+    if (count != INNER_ITERS) {
+      System.out.println("DeadReferenceSafeTest: Final count wrong: " + count);
+    }
+    reset(INNER_ITERS);
+  }
+}
diff --git a/test/1339-dead-reference-safe/src/DeadReferenceUnsafeTest.java b/test/1339-dead-reference-safe/src/DeadReferenceUnsafeTest.java
new file mode 100644
index 0000000..84774da
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/DeadReferenceUnsafeTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public final class DeadReferenceUnsafeTest {
+  static AtomicInteger nFinalized = new AtomicInteger(0);
+  private static final int INNER_ITERS = 10;
+  static int count;
+  int n = 1;
+
+  private static void $noinline$loop() {
+    DeadReferenceUnsafeTest x;
+    // The loop allocates INNER_ITERS DeadReferenceUnsafeTest objects.
+    for (int i = 0; i < INNER_ITERS; ++i) {
+      // We've allocated i objects so far.
+      x = new DeadReferenceUnsafeTest();
+      count += x.n;
+      // x is dead here.
+      if (i == 5) {
+        // Without dead reference elimination, the last object should be kept around,
+        // and only 5 objects should be relcaimed here.
+        Main.$noinline$gcAndCheck(nFinalized, 5, "DeadReferenceUnsafe",
+            "Failed to keep dead reference live in unannotated code!");
+      }
+    }
+  }
+
+  private static void reset(int expected_count) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    if (nFinalized.get() != expected_count) {
+      System.out.println("DeadReferenceUnsafeTest: Wrong number of finalized objects:"
+                         + nFinalized.get());
+    }
+    nFinalized.set(0);
+  }
+
+  protected void finalize() {
+    nFinalized.incrementAndGet();
+  }
+
+  public static void runTest() {
+    try {
+      Main.ensureCompiled(DeadReferenceUnsafeTest.class, "$noinline$loop");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Unexpectedly threw " + e);
+    }
+
+    $noinline$loop();
+
+    if (count != INNER_ITERS) {
+      System.out.println("DeadReferenceUnsafeTest: Final count wrong: " + count);
+    }
+    reset(INNER_ITERS);
+  }
+}
diff --git a/test/1339-dead-reference-safe/src/Main.java b/test/1339-dead-reference-safe/src/Main.java
new file mode 100644
index 0000000..46b533a
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/Main.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Main {
+
+  // Ensure that the "loop" method is compiled. Otherwise we currently have no real way to get rid
+  // of dead references. Return true if it looks like we succeeded.
+  public static boolean ensureCompiled(Class cls, String methodName) throws NoSuchMethodException {
+    Method m = cls.getDeclaredMethod(methodName);
+    if (isAotCompiled(cls, methodName)) {
+      return true;
+    } else {
+      ensureMethodJitCompiled(m);
+      if (hasJitCompiledEntrypoint(cls, methodName)) {
+        return true;
+      }
+      return false;
+    }
+  }
+
+  // Garbage collect and check that the atomic counter has the expected value.
+  // Exped value of -1 means don't care.
+  // Noinline because we don't want the inlining here to interfere with the ReachabilitySensitive
+  // analysis.
+  public static void $noinline$gcAndCheck(AtomicInteger counter, int expected, String label,
+                                          String msg) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    int count = counter.get();
+    System.out.println(label + " count: " + count);
+    if (counter.get() != expected && expected != -1) {
+      System.out.println(msg);
+    }
+  }
+
+  public static void main(String[] args) {
+    System.loadLibrary(args[0]);
+    // Run several variations of the same test with different reachability annotations, etc.
+    // Only the DeadReferenceSafeTest should finalize every previously allocated object.
+    DeadReferenceUnsafeTest.runTest();
+    DeadReferenceSafeTest.runTest();
+    ReachabilitySensitiveTest.runTest();
+    ReachabilitySensitiveFunTest.runTest();
+    ReachabilityFenceTest.runTest();
+  }
+  public static native void ensureMethodJitCompiled(Method meth);
+  public static native boolean hasJitCompiledEntrypoint(Class<?> cls, String methodName);
+  public static native boolean isAotCompiled(Class<?> cls, String methodName);
+}
diff --git a/test/1339-dead-reference-safe/src/ReachabilityFenceTest.java b/test/1339-dead-reference-safe/src/ReachabilityFenceTest.java
new file mode 100644
index 0000000..d4befde
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/ReachabilityFenceTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// DeadReferenceSafeTest, but with a reachabilityFence.
+
+import dalvik.annotation.optimization.DeadReferenceSafe;
+import java.lang.ref.Reference;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@DeadReferenceSafe
+public final class ReachabilityFenceTest {
+  static AtomicInteger nFinalized = new AtomicInteger(0);
+  private static final int INNER_ITERS = 10;
+  static int count;
+  int n = 1;
+
+  private static void $noinline$loop() {
+    ReachabilityFenceTest x;
+    // Each loop allocates INNER_ITERS ReachabilitySenstiveTest objects.
+    for (int i = 0; i < INNER_ITERS; ++i) {
+      // We've allocated i objects so far.
+      x = new ReachabilityFenceTest();
+      count += x.n;
+      // x is dead here.
+      if (i == 5) {
+        // The rechabilityFence should keep the last allocated object reachable.
+        // Thus the last instance should not be finalized.
+        Main.$noinline$gcAndCheck(nFinalized, 5, "ReachabilityFence",
+            "reachabilityFence failed to keep object live.");
+      }
+      Reference.reachabilityFence(x);
+    }
+  }
+
+  private static void reset(int expected_count) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    if (nFinalized.get() != expected_count) {
+      System.out.println("ReachabilityFenceTest: Wrong number of finalized objects:"
+                         + nFinalized.get());
+    }
+    nFinalized.set(0);
+  }
+
+  protected void finalize() {
+    nFinalized.incrementAndGet();
+  }
+
+  public static void runTest() {
+    try {
+      Main.ensureCompiled(ReachabilityFenceTest.class, "$noinline$loop");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Unexpectedly threw " + e);
+    }
+
+    $noinline$loop();
+
+    if (count != INNER_ITERS) {
+      System.out.println("ReachabilityFenceTest: Final count wrong: " + count);
+    }
+    reset(INNER_ITERS);
+  }
+}
diff --git a/test/1339-dead-reference-safe/src/ReachabilitySensitiveFunTest.java b/test/1339-dead-reference-safe/src/ReachabilitySensitiveFunTest.java
new file mode 100644
index 0000000..2c66146
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/ReachabilitySensitiveFunTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// DeadReferenceSafeTest, but with a ReachabilitySensitive annotation.
+
+import dalvik.annotation.optimization.DeadReferenceSafe;
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@DeadReferenceSafe
+public final class ReachabilitySensitiveFunTest {
+  static AtomicInteger nFinalized = new AtomicInteger(0);
+  private static final int INNER_ITERS = 10;
+  static int count;
+  int n = 1;
+  @ReachabilitySensitive
+  int getN() {
+    return n;
+  }
+
+  private static void $noinline$loop() {
+    ReachabilitySensitiveFunTest x;
+    // The loop allocates INNER_ITERS ReachabilitySensitiveTest objects.
+    for (int i = 0; i < INNER_ITERS; ++i) {
+      // We've allocated i objects so far.
+      x = new ReachabilitySensitiveFunTest();
+      // ReachabilitySensitive reference.
+      count += x.getN();
+      // x is dead here.
+      if (i == 5) {
+        // Since there is a ReachabilitySensitive call, x should be kept live
+        // until it is reassigned. Thus the last instance should not be finalized.
+        Main.$noinline$gcAndCheck(nFinalized, 5, "ReachabilitySensitiveFun",
+            "@ReachabilitySensitive call failed to keep object live.");
+      }
+    }
+  }
+
+  private static void reset(int expected_count) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    if (nFinalized.get() != expected_count) {
+      System.out.println("ReachabilitySensitiveFunTest: Wrong number of finalized objects:"
+                         + nFinalized.get());
+    }
+    nFinalized.set(0);
+  }
+
+  protected void finalize() {
+    nFinalized.incrementAndGet();
+  }
+
+  public static void runTest() {
+    try {
+      Main.ensureCompiled(ReachabilitySensitiveFunTest.class, "$noinline$loop");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Unexpectedly threw " + e);
+    }
+
+    $noinline$loop();
+
+    if (count != INNER_ITERS) {
+      System.out.println("ReachabilitySensitiveFunTest: Final count wrong: " + count);
+    }
+    reset(INNER_ITERS);
+  }
+}
diff --git a/test/1339-dead-reference-safe/src/ReachabilitySensitiveTest.java b/test/1339-dead-reference-safe/src/ReachabilitySensitiveTest.java
new file mode 100644
index 0000000..aff43b6
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/ReachabilitySensitiveTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// DeadReferenceSafeTest, but with a ReachabilitySensitive annotation.
+
+import dalvik.annotation.optimization.DeadReferenceSafe;
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@DeadReferenceSafe
+public final class ReachabilitySensitiveTest {
+  static AtomicInteger nFinalized = new AtomicInteger(0);
+  private static final int INNER_ITERS = 10;
+  static int count;
+  @ReachabilitySensitive
+  int n = 1;
+
+  private static void $noinline$loop() {
+    ReachabilitySensitiveTest x;
+    // The loop allocates INNER_ITERS ReachabilitySensitiveTest objects.
+    for (int i = 0; i < INNER_ITERS; ++i) {
+      // We've allocated i objects so far.
+      x = new ReachabilitySensitiveTest();
+      // ReachabilitySensitive reference.
+      count += x.n;
+      // x is dead here.
+      if (i == 5) {
+        // Since there is a ReachabilitySensitive reference to x.n, x should be kept live
+        // until it is reassigned. Thus the last instance should not be finalized.
+        Main.$noinline$gcAndCheck(nFinalized, 5, "ReachabilitySensitive",
+            "@ReachabilitySensitive failed to keep object live.");
+      }
+    }
+  }
+
+  private static void reset(int expected_count) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    if (nFinalized.get() != expected_count) {
+      System.out.println("ReachabilitySensitiveTest: Wrong number of finalized objects:"
+                         + nFinalized.get());
+    }
+    nFinalized.set(0);
+  }
+
+  protected void finalize() {
+    nFinalized.incrementAndGet();
+  }
+
+  public static void runTest() {
+    try {
+      Main.ensureCompiled(ReachabilitySensitiveTest.class, "$noinline$loop");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Unexpectedly threw " + e);
+    }
+
+    $noinline$loop();
+
+    if (count != INNER_ITERS) {
+      System.out.println("ReachabilitySensitiveTest: Final count wrong: " + count);
+    }
+    reset(INNER_ITERS);
+  }
+}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 9c01ba9..e32d23d 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1088,6 +1088,7 @@
                   "999-redefine-hiddenapi",
                   "1000-non-moving-space-stress",
                   "1001-app-image-regions",
+                  "1339-dead-reference-safe",
                   "1951-monitor-enter-no-suspend",
                   "1957-error-ext"],
         "variant": "jvm",
@@ -1172,6 +1173,11 @@
         "description": ["Tests are expected to fail with baseline."]
     },
     {
+        "tests": ["1339-dead-reference-safe"],
+        "variant": "debuggable",
+        "description": [ "Fails to eliminate dead reference when debuggable." ]
+    },
+    {
         "tests": ["708-jit-cache-churn"],
         "variant": "jit-on-first-use",
         "bug": "b/120112467",
diff --git a/tools/libcore_gcstress_failures.txt b/tools/libcore_gcstress_failures.txt
index 34ede69..9af2f64 100644
--- a/tools/libcore_gcstress_failures.txt
+++ b/tools/libcore_gcstress_failures.txt
@@ -32,8 +32,9 @@
           "libcore.java.text.DecimalFormatTest#testCurrencySymbolSpacing",
           "libcore.java.text.SimpleDateFormatTest#testLocales",
           "org.apache.harmony.tests.java.lang.ref.ReferenceQueueTest#test_remove",
-          "org.apache.harmony.tests.java.text.DateFormatTest#test_getAvailableLocales",
+          "org.apache.harmony.tests.java.lang.ProcessManagerTest#testSleep",
           "org.apache.harmony.tests.java.lang.String2Test#test_getBytes",
+          "org.apache.harmony.tests.java.text.DateFormatTest#test_getAvailableLocales",
           "org.apache.harmony.tests.java.util.TimerTest#testOverdueTaskExecutesImmediately",
           "org.apache.harmony.tests.java.util.WeakHashMapTest#test_keySet_hasNext"]
 }
diff --git a/tools/veridex/hidden_api.cc b/tools/veridex/hidden_api.cc
index 1dae93a..efb01f7 100644
--- a/tools/veridex/hidden_api.cc
+++ b/tools/veridex/hidden_api.cc
@@ -37,7 +37,7 @@
     CHECK(success) << "Unknown ApiList flag: " << str;
     CHECK(membership.IsValid()) << "Invalid ApiList: " << membership;
 
-    if (sdk_uses_only != (membership == hiddenapi::ApiList::Whitelist())) {
+    if (sdk_uses_only != membership.Contains(hiddenapi::ApiList::Whitelist())) {
       // Either we want only SDK uses and this is not a whitelist entry,
       // or we want only non-SDK uses and this is a whitelist entry.
       continue;