Add option to force all code to be deoptimizable

Currently this can only be passed during runtime startup. We will add
support for doing it from the zygote in the future.

Bug: 28769520
Bug: 32369913

Test: m test-art-host

Change-Id: I5eb16887ea14b140217c123b3effd47c5c8b2768
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 6d45dad..4b39c5c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2828,6 +2828,13 @@
     return true;
   }
 
+  if (runtime->IsFullyDeoptable()) {
+    // We need to be able to deoptimize at any time so we should always just ignore precompiled
+    // code and go to the interpreter assuming we don't already have jitted code.
+    jit::Jit* jit = Runtime::Current()->GetJit();
+    return (jit == nullptr) || !jit->GetCodeCache()->ContainsPc(quick_code);
+  }
+
   if (runtime->IsNativeDebuggable()) {
     DCHECK(runtime->UseJitCompilation() && runtime->GetJit()->JitAtFirstUse());
     // If we are doing native debugging, ignore application's AOT code,
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 56eab5e..e1022b0 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -300,6 +300,8 @@
       .Define("-Xplugin:_")
           .WithType<std::vector<Plugin>>().AppendValues()
           .IntoKey(M::Plugins)
+      .Define("-Xfully-deoptable")
+          .IntoKey(M::FullyDeoptable)
       .Ignore({
           "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
           "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 6d849c4..6177ef9 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -239,6 +239,7 @@
       force_native_bridge_(false),
       is_native_bridge_loaded_(false),
       is_native_debuggable_(false),
+      is_fully_deoptable_(false),
       zygote_max_failed_boots_(0),
       experimental_flags_(ExperimentalFlags::kNone),
       oat_file_manager_(nullptr),
@@ -764,6 +765,9 @@
 }
 
 bool Runtime::IsDebuggable() const {
+  if (IsFullyDeoptable()) {
+    return true;
+  }
   const OatFile* oat_file = GetOatFileManager().GetPrimaryOatFile();
   return oat_file != nullptr && oat_file->IsDebuggable();
 }
@@ -987,6 +991,8 @@
   verify_ = runtime_options.GetOrDefault(Opt::Verify);
   allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback);
 
+  is_fully_deoptable_ = runtime_options.Exists(Opt::FullyDeoptable);
+
   no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
   force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);
 
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 364290d..6c63db4 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -594,6 +594,14 @@
 
   bool IsDebuggable() const;
 
+  bool IsFullyDeoptable() const {
+    return is_fully_deoptable_;
+  }
+
+  void SetFullyDeoptable(bool value) {
+    is_fully_deoptable_ = value;
+  }
+
   bool IsNativeDebuggable() const {
     return is_native_debuggable_;
   }
@@ -859,6 +867,9 @@
   // Whether we are running under native debugger.
   bool is_native_debuggable_;
 
+  // Whether we are expected to be deoptable at all points.
+  bool is_fully_deoptable_;
+
   // The maximum number of failed boots we allow before pruning the dalvik cache
   // and trying again. This option is only inspected when we're running as a
   // zygote.
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index b01a570..d1970fe 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -121,6 +121,7 @@
 RUNTIME_OPTIONS_KEY (std::vector<ti::Agent>,         AgentLib)  // -agentlib:<libname>=<options>, Requires -Xexperimental:agents
 RUNTIME_OPTIONS_KEY (std::vector<ti::Agent>,         AgentPath)  // -agentpath:<libname>=<options>, Requires -Xexperimental:agents
 RUNTIME_OPTIONS_KEY (std::vector<Plugin>,            Plugins)  // -Xplugin:<library> Requires -Xexperimental:runtime-plugins
+RUNTIME_OPTIONS_KEY (Unit,                           FullyDeoptable)  // -Xfully-deoptable
 
 // Not parse-able from command line, but can be provided explicitly.
 // (Do not add anything here that is defined in ParsedOptions::MakeParser)
diff --git a/test/902-hello-transformation/run b/test/902-hello-transformation/run
index 204e4cc..3755d1d 100755
--- a/test/902-hello-transformation/run
+++ b/test/902-hello-transformation/run
@@ -39,5 +39,6 @@
                    --experimental runtime-plugins \
                    --runtime-option -agentpath:${agent}=902-hello-transformation,${arg} \
                    --android-runtime-option -Xplugin:${plugin} \
+                   --android-runtime-option -Xfully-deoptable \
                    ${other_args} \
                    --args ${lib}