Compilation filter

This CL introduces a static compilation filter mechanism intended
to allow us to reduce compilation time and space requirements until
we have a profiling mechanism in place.

It supports 5 modes of filtering:

   o interpret-only (compile nothing)
   o deferred-compilation (compile only those methods believe to be
     compute-intensive)
   o space (optimized for space)
   o balanced (best return on space investment)
   o speed (compile everything)

A future CL will allow the default filtering mode to be set
via system property.  For now, you can pass it in via command
line as follows:

   dalvikvm -compiler-filter:[interpret-only|defer-compilation|
                              space|balanced|speed]

or dex2oat --runtime-arg -compiler-filter:[one of the above modes]

Creating a file named art/SMALL_ART will force the filter
default to interpret-only.  Later on we'll move this capability
to a persistent system property.

or modify kDefaultCompilerFilter in runtime.h

It also changes the compiler driver to allow the compilers to
decline to compile a method by return NULL.

Change-Id: Ic73411818f8bb845a4a19a05b0395c50902c534f
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 84f186d..6052993 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -609,6 +609,28 @@
   oat_location_option_string += oat_cache_filename;
   const char* oat_location_option = oat_location_option_string.c_str();
 
+  std::string oat_compiler_filter_string("-compiler-filter:");
+  switch (Runtime::Current()->GetCompilerFilter()) {
+    case Runtime::kInterpretOnly:
+      oat_compiler_filter_string += "interpret-only";
+      break;
+    case Runtime::kDeferCompilation:
+      oat_compiler_filter_string += "defer-compilation";
+      break;
+    case Runtime::kSpace:
+      oat_compiler_filter_string += "space";
+      break;
+    case Runtime::kBalanced:
+      oat_compiler_filter_string += "balanced";
+      break;
+    case Runtime::kSpeed:
+      oat_compiler_filter_string += "speed";
+      break;
+    default:
+      LOG(FATAL) << "Unexpected case.";
+  }
+  const char* oat_compiler_filter_option = oat_compiler_filter_string.c_str();
+
   // fork and exec dex2oat
   pid_t pid = fork();
   if (pid == 0) {
@@ -622,6 +644,7 @@
                        << " --runtime-arg -Xmx64m"
                        << " --runtime-arg -classpath"
                        << " --runtime-arg " << class_path
+                       << " --runtime-arg " << oat_compiler_filter_option
 #if !defined(ART_TARGET)
                        << " --host"
 #endif
@@ -635,6 +658,7 @@
           "--runtime-arg", "-Xmx64m",
           "--runtime-arg", "-classpath",
           "--runtime-arg", class_path,
+          "--runtime-arg", oat_compiler_filter_option,
 #if !defined(ART_TARGET)
           "--host",
 #endif
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5298181..70d8816 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -355,9 +355,12 @@
   parsed->hook_exit_ = exit;
   parsed->hook_abort_ = NULL;  // We don't call abort(3) by default; see Runtime::Abort.
 
-  parsed->small_mode_ = false;
-  parsed->small_mode_method_threshold_ = Runtime::kDefaultSmallModeMethodThreshold;
-  parsed->small_mode_method_dex_size_limit_ = Runtime::kDefaultSmallModeMethodDexSizeLimit;
+  parsed->compiler_filter_ = Runtime::kDefaultCompilerFilter;
+  parsed->huge_method_threshold_ = Runtime::kDefaultHugeMethodThreshold;
+  parsed->large_method_threshold_ = Runtime::kDefaultLargeMethodThreshold;
+  parsed->small_method_threshold_ = Runtime::kDefaultSmallMethodThreshold;
+  parsed->tiny_method_threshold_ = Runtime::kDefaultTinyMethodThreshold;
+  parsed->num_dex_methods_threshold_ = Runtime::kDefaultNumDexMethodsThreshold;
 
   parsed->sea_ir_mode_ = false;
 //  gLogVerbosity.class_linker = true;  // TODO: don't check this in!
@@ -572,14 +575,28 @@
       Trace::SetDefaultClockSource(kProfilerClockSourceWall);
     } else if (option == "-Xprofile:dualclock") {
       Trace::SetDefaultClockSource(kProfilerClockSourceDual);
-    } else if (option == "-small") {
-      parsed->small_mode_ = true;
+    } else if (option == "-compiler-filter:interpret-only") {
+      parsed->compiler_filter_ = kInterpretOnly;
+    } else if (option == "-compiler-filter:defer-compilation") {
+      parsed->compiler_filter_ = kDeferCompilation;
+    } else if (option == "-compiler-filter:space") {
+      parsed->compiler_filter_ = kSpace;
+    } else if (option == "-compiler-filter:balanced") {
+      parsed->compiler_filter_ = kBalanced;
+    } else if (option == "-compiler-filter:speed") {
+      parsed->compiler_filter_ = kSpeed;
     } else if (option == "-sea_ir") {
       parsed->sea_ir_mode_ = true;
-    } else if (StartsWith(option, "-small-mode-methods-max:")) {
-      parsed->small_mode_method_threshold_ = ParseIntegerOrDie(option);
-    } else if (StartsWith(option, "-small-mode-methods-size-max:")) {
-      parsed->small_mode_method_dex_size_limit_ = ParseIntegerOrDie(option);
+    } else if (StartsWith(option, "-huge-method-max:")) {
+      parsed->huge_method_threshold_ = ParseIntegerOrDie(option);
+    } else if (StartsWith(option, "-large-method-max:")) {
+      parsed->large_method_threshold_ = ParseIntegerOrDie(option);
+    } else if (StartsWith(option, "-small-method-max:")) {
+      parsed->small_method_threshold_ = ParseIntegerOrDie(option);
+    } else if (StartsWith(option, "-tiny-method-max:")) {
+      parsed->tiny_method_threshold_ = ParseIntegerOrDie(option);
+    } else if (StartsWith(option, "-num-dex-methods-max:")) {
+      parsed->num_dex_methods_threshold_ = ParseIntegerOrDie(option);
     } else {
       if (!ignore_unrecognized) {
         // TODO: print usage via vfprintf
@@ -809,9 +826,12 @@
   is_zygote_ = options->is_zygote_;
   is_concurrent_gc_enabled_ = options->is_concurrent_gc_enabled_;
 
-  small_mode_ = options->small_mode_;
-  small_mode_method_threshold_ = options->small_mode_method_threshold_;
-  small_mode_method_dex_size_limit_ = options->small_mode_method_dex_size_limit_;
+  compiler_filter_ = options->compiler_filter_;
+  huge_method_threshold_ = options->huge_method_threshold_;
+  large_method_threshold_ = options->large_method_threshold_;
+  small_method_threshold_ = options->small_method_threshold_;
+  tiny_method_threshold_ = options->tiny_method_threshold_;
+  num_dex_methods_threshold_ = options->num_dex_methods_threshold_;
 
   sea_ir_mode_ = options->sea_ir_mode_;
   vfprintf_ = options->hook_vfprintf_;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 47fff29..d67265a 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -63,15 +63,25 @@
  public:
   typedef std::vector<std::pair<std::string, const void*> > Options;
 
-  // In small mode, apps with fewer than this number of methods will be compiled
-  // anyways.
-  // TODO: come up with a reasonable default.
-  static const size_t kDefaultSmallModeMethodThreshold = 0;
+  enum CompilerFilter {
+    kInterpretOnly,       // Compile nothing.
+    kDeferCompilation,    // Temporary minimal compilation, will redo during device idle time.
+    kSpace,               // Maximize space savings.
+    kBalanced,            // Try to get the best performance return on compilation investment.
+    kSpeed                // Compile all methods.
+  };
 
-  // In small mode, methods smaller than this dex op count limit will get compiled
-  // anyways.
-  // TODO: come up with a reasonable default.
-  static const size_t kDefaultSmallModeMethodDexSizeLimit = 300;
+  // Guide heuristics to determine whether to compile method if profile data not available.
+#if ART_SMALL_MODE
+  static const CompilerFilter kDefaultCompilerFilter = kInterpretOnly;
+#else
+  static const CompilerFilter kDefaultCompilerFilter = kSpeed;
+#endif
+  static const size_t kDefaultHugeMethodThreshold = 6000;
+  static const size_t kDefaultLargeMethodThreshold = 1000;
+  static const size_t kDefaultSmallMethodThreshold = 200;
+  static const size_t kDefaultTinyMethodThreshold = 10;
+  static const size_t kDefaultNumDexMethodsThreshold = 900;
 
   class ParsedOptions {
    public:
@@ -108,11 +118,12 @@
     void (*hook_exit_)(jint status);
     void (*hook_abort_)();
     std::vector<std::string> properties_;
-    bool small_mode_;
-
-    size_t small_mode_method_threshold_;
-    size_t small_mode_method_dex_size_limit_;
-
+    CompilerFilter compiler_filter_;
+    size_t huge_method_threshold_;
+    size_t large_method_threshold_;
+    size_t small_method_threshold_;
+    size_t tiny_method_threshold_;
+    size_t num_dex_methods_threshold_;
     bool sea_ir_mode_;
 
    private:
@@ -145,21 +156,32 @@
     sea_ir_mode_ = sea_ir_mode;
   }
 
-  bool IsSmallMode() const {
-      return small_mode_;
+  CompilerFilter GetCompilerFilter() const {
+    return compiler_filter_;
   }
 
-
-  void SetSmallMode(bool small_mode) {
-      small_mode_ = small_mode;
+  void SetCompilerFilter(CompilerFilter compiler_filter) {
+    compiler_filter_ = compiler_filter;
   }
 
-  size_t GetSmallModeMethodThreshold() const {
-      return small_mode_method_threshold_;
+  size_t GetHugeMethodThreshold() const {
+    return huge_method_threshold_;
   }
 
-  size_t GetSmallModeMethodDexSizeLimit() const {
-      return small_mode_method_dex_size_limit_;
+  size_t GetLargeMethodThreshold() const {
+    return large_method_threshold_;
+  }
+
+  size_t GetSmallMethodThreshold() const {
+    return small_method_threshold_;
+  }
+
+  size_t GetTinyMethodThreshold() const {
+    return tiny_method_threshold_;
+  }
+
+  size_t GetNumDexMethodsThreshold() const {
+      return num_dex_methods_threshold_;
   }
 
   const std::string& GetHostPrefix() const {
@@ -384,9 +406,12 @@
   bool is_zygote_;
   bool is_concurrent_gc_enabled_;
 
-  bool small_mode_;
-  size_t small_mode_method_threshold_;
-  size_t small_mode_method_dex_size_limit_;
+  CompilerFilter compiler_filter_;
+  size_t huge_method_threshold_;
+  size_t large_method_threshold_;
+  size_t small_method_threshold_;
+  size_t tiny_method_threshold_;
+  size_t num_dex_methods_threshold_;
 
   bool sea_ir_mode_;
 
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 9f0d911..f1de565 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4180,16 +4180,7 @@
   if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
     return false;
   }
-
-  const Runtime* runtime = Runtime::Current();
-  if (runtime->IsSmallMode() && runtime->UseCompileTimeClassPath()) {
-    // In Small mode, we only compile small methods.
-    const uint32_t code_size = code_item->insns_size_in_code_units_;
-    return (code_size < runtime->GetSmallModeMethodDexSizeLimit());
-  } else {
-    // In normal mode, we compile everything.
-    return true;
-  }
+  return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly);
 }
 
 ReaderWriterMutex* MethodVerifier::dex_gc_maps_lock_ = NULL;