Support compiler filters for boot classpath

image_writer.cc
  Remove assumption that all methods in the boot classpath are compiled

oat_writer.cc
  Don't skip writing ArtMethod::quick_code_offset_ for methods that need resolution, leave that to ImageWriter

dex2oat.cc
  Allow dex2dex compilation of image dex files by making the in memory pages writable in all cases, not just app case.

oatdump.cc
  dump new OatHeader fields
  use ImageSpace.GetImageFilename, not command line image filename, since location may be in dalvik-cache
  remove inaccurate check about non-null GC map

quick_trampoline_entrypoints.cc
  add and improve some DCHECKS that were useful while debugging

class_linker.cc
image_space.cc
  fix double facepalm

parsed_options.cc
  fix zygote logging to not skip values to two part options like -classpath <foo>

runtime.cc
  wireup parsed compiler options to runtime

Change-Id: Iad314df0b80623c0663d61713d5098297ab9ac87
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 69e0950..e3114eb 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -635,15 +635,19 @@
       // Use original code if it exists. Otherwise, set the code pointer to the resolution
       // trampoline.
       const byte* quick_code = GetOatAddress(orig->GetQuickOatCodeOffset());
-      if (quick_code != nullptr) {
+      if (quick_code != nullptr &&
+          (!orig->IsStatic() || orig->IsConstructor() || orig->GetDeclaringClass()->IsInitialized())) {
+        // We have code for a non-static or initialized method, just use the code.
         copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(quick_code);
+      } else if (quick_code == nullptr && orig->IsNative() && !orig->IsStatic()) {
+        // Non-static native method missing compiled code, use generic JNI version.
+        copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_generic_jni_trampoline_offset_));
+      } else if (quick_code == nullptr && !orig->IsNative()) {
+        // We don't have code at all for a non-native method, use the interpreter.
+        copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_to_interpreter_bridge_offset_));
       } else {
-        if (orig->IsNative() && !orig->IsStatic()) {
-          // non-static native method missing compiled code, use generic JNI version
-          copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_generic_jni_trampoline_offset_));
-        } else {
-          copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_resolution_trampoline_offset_));
-        }
+        // We have code for a static method, but need to go through the resolution stub for class initialization.
+        copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_resolution_trampoline_offset_));
       }
       const byte* portable_code = GetOatAddress(orig->GetPortableOatCodeOffset());
       if (portable_code != nullptr) {
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 181240e..186ab38 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -506,15 +506,8 @@
     method->SetCoreSpillMask(core_spill_mask);
     method->SetFpSpillMask(fp_spill_mask);
     method->SetOatMappingTableOffset(mapping_table_offset);
-    // Don't overwrite static method trampoline
-    if (!method->IsStatic() || method->IsConstructor() ||
-        method->GetDeclaringClass()->IsInitialized()) {
-      // TODO: record portable code offsets: method->SetPortableOatCodeOffset(portable_code_offset);
-      method->SetQuickOatCodeOffset(quick_code_offset);
-    } else {
-      method->SetEntryPointFromPortableCompiledCode(nullptr);
-      method->SetEntryPointFromQuickCompiledCode(nullptr);
-    }
+    // Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking.
+    method->SetQuickOatCodeOffset(quick_code_offset);
     method->SetOatVmapTableOffset(vmap_table_offset);
     method->SetOatNativeGcMapOffset(gc_map_offset);
   }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 9f6b454..afa8495 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1166,12 +1166,11 @@
         LOG(INFO) << "Wrote input to " << tmp_file_name;
       }
     }
-
-    // Ensure opened dex files are writable for dex-to-dex transformations.
-    for (const auto& dex_file : dex_files) {
-      if (!dex_file->EnableWrite()) {
-        PLOG(ERROR) << "Failed to make .dex file writeable '" << dex_file->GetLocation() << "'\n";
-      }
+  }
+  // Ensure opened dex files are writable for dex-to-dex transformations.
+  for (const auto& dex_file : dex_files) {
+    if (!dex_file->EnableWrite()) {
+      PLOG(ERROR) << "Failed to make .dex file writeable '" << dex_file->GetLocation() << "'\n";
     }
   }
 
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index bbeb802..841a478 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -126,8 +126,36 @@
     os << "DEX FILE COUNT:\n";
     os << oat_header.GetDexFileCount() << "\n\n";
 
-    os << "EXECUTABLE OFFSET:\n";
-    os << StringPrintf("0x%08x\n\n", oat_header.GetExecutableOffset());
+#define DUMP_OAT_HEADER_OFFSET(label, offset) \
+    os << label " OFFSET:\n"; \
+    os << StringPrintf("0x%08x", oat_header.offset()); \
+    if (oat_header.offset() != 0) { \
+      os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \
+    } \
+    os << StringPrintf("\n\n");
+
+    DUMP_OAT_HEADER_OFFSET("EXECUTABLE", GetExecutableOffset);
+    DUMP_OAT_HEADER_OFFSET("INTERPRETER TO INTERPRETER BRIDGE",
+                           GetInterpreterToInterpreterBridgeOffset);
+    DUMP_OAT_HEADER_OFFSET("INTERPRETER TO COMPILED CODE BRIDGE",
+                           GetInterpreterToCompiledCodeBridgeOffset);
+    DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP",
+                           GetJniDlsymLookupOffset);
+    DUMP_OAT_HEADER_OFFSET("PORTABLE IMT CONFLICT TRAMPOLINE",
+                           GetPortableImtConflictTrampolineOffset);
+    DUMP_OAT_HEADER_OFFSET("PORTABLE RESOLUTION TRAMPOLINE",
+                           GetPortableResolutionTrampolineOffset);
+    DUMP_OAT_HEADER_OFFSET("PORTABLE TO INTERPRETER BRIDGE",
+                           GetPortableToInterpreterBridgeOffset);
+    DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE",
+                           GetQuickGenericJniTrampolineOffset);
+    DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE",
+                           GetQuickImtConflictTrampolineOffset);
+    DUMP_OAT_HEADER_OFFSET("QUICK RESOLUTION TRAMPOLINE",
+                           GetQuickResolutionTrampolineOffset);
+    DUMP_OAT_HEADER_OFFSET("QUICK TO INTERPRETER BRIDGE",
+                           GetQuickToInterpreterBridgeOffset);
+#undef DUMP_OAT_HEADER_OFFSET
 
     os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
@@ -214,7 +242,9 @@
         continue;
       }
       offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader()));
-      for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
+      for (size_t class_def_index = 0;
+           class_def_index < dex_file->NumClassDefs();
+           class_def_index++) {
         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
         UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
         const byte* class_data = dex_file->GetClassData(class_def);
@@ -264,7 +294,9 @@
       os << "NOT FOUND: " << error_msg << "\n\n";
       return;
     }
-    for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
+    for (size_t class_def_index = 0;
+         class_def_index < dex_file->NumClassDefs();
+         class_def_index++) {
       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
       const char* descriptor = dex_file->GetClassDescriptor(class_def);
       UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file.GetOatClass(class_def_index));
@@ -389,8 +421,9 @@
         SirtRef<mirror::DexCache> dex_cache(
             soa.Self(), runtime->GetClassLinker()->FindDexCache(dex_file));
         SirtRef<mirror::ClassLoader> class_loader(soa.Self(), nullptr);
-        verifier::MethodVerifier verifier(&dex_file, &dex_cache, &class_loader, &class_def, code_item,
-                                          dex_method_idx, nullptr, method_access_flags, true, true);
+        verifier::MethodVerifier verifier(&dex_file, &dex_cache, &class_loader, &class_def,
+                                          code_item, dex_method_idx, nullptr, method_access_flags,
+                                          true, true);
         verifier.Verify();
         DumpCode(indent2_os, &verifier, oat_method, code_item);
       } else {
@@ -654,7 +687,8 @@
                     uint32_t method_access_flags) {
     if ((method_access_flags & kAccNative) == 0) {
       ScopedObjectAccess soa(Thread::Current());
-      SirtRef<mirror::DexCache> dex_cache(soa.Self(), Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file));
+      SirtRef<mirror::DexCache> dex_cache(
+          soa.Self(), Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file));
       SirtRef<mirror::ClassLoader> class_loader(soa.Self(), nullptr);
       verifier::MethodVerifier::VerifyMethodAndDump(os, dex_method_idx, dex_file, dex_cache,
                                                     class_loader, &class_def, code_item, NULL,
@@ -701,12 +735,10 @@
 
 class ImageDumper {
  public:
-  explicit ImageDumper(std::ostream* os, const std::string& image_filename,
-                       gc::space::ImageSpace& image_space,
+  explicit ImageDumper(std::ostream* os, gc::space::ImageSpace& image_space,
                        const ImageHeader& image_header, bool dump_raw_mapping_table,
                        bool dump_raw_gc_map)
-      : os_(os), image_filename_(image_filename),
-        image_space_(image_space), image_header_(image_header),
+      : os_(os), image_space_(image_space), image_header_(image_header),
         dump_raw_mapping_table_(dump_raw_mapping_table),
         dump_raw_gc_map_(dump_raw_gc_map) {}
 
@@ -772,7 +804,8 @@
     os << "\n";
 
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename_);
+    std::string image_filename = image_space_.GetImageFilename();
+    std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename);
     os << "OAT LOCATION: " << oat_location;
     os << "\n";
     std::string error_msg;
@@ -836,17 +869,12 @@
       os_ = saved_os;
     }
     os << "STATS:\n" << std::flush;
-    UniquePtr<File> file(OS::OpenFileForReading(image_filename_.c_str()));
+    UniquePtr<File> file(OS::OpenFileForReading(image_filename.c_str()));
     if (file.get() == NULL) {
-      std::string cache_location(GetDalvikCacheFilenameOrDie(image_filename_.c_str()));
-      file.reset(OS::OpenFileForReading(cache_location.c_str()));
-      if (file.get() == NULL) {
-          LOG(WARNING) << "Failed to find image in " << image_filename_
-                       << " and " << cache_location;
-      }
+      LOG(WARNING) << "Failed to find image in " << image_filename;
     }
     if (file.get() != NULL) {
-        stats_.file_bytes = file->GetLength();
+      stats_.file_bytes = file->GetLength();
     }
     size_t header_bytes = sizeof(ImageHeader);
     stats_.header_bytes = header_bytes;
@@ -1027,7 +1055,8 @@
           indent_os << StringPrintf("%d to %zd: ", i, i + run);
           i = i + run;
         }
-        mirror::Class* value_class = value == NULL ? obj_class->GetComponentType() : value->GetClass();
+        mirror::Class* value_class =
+            (value == NULL) ? obj_class->GetComponentType() : value->GetClass();
         PrettyObjectValue(indent_os, value_class, value);
       }
     } else if (obj->IsClass()) {
@@ -1063,10 +1092,6 @@
         DCHECK(method->GetNativeGcMap() == NULL) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
       } else {
-        // TODO: we check there is a GC map here, we may not have a GC map if the code is pointing
-        //       to the quick/portable to interpreter bridge.
-        CHECK(method->GetNativeGcMap() != NULL) << PrettyMethod(method);
-
         const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem();
         size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
         state->stats_.dex_instruction_bytes += dex_instruction_bytes;
@@ -1363,12 +1388,18 @@
                          "large_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
                          "large_method_code_bytes      = %8zd (%2.0f%% of oat file bytes)\n\n",
                          oat_file_bytes,
-                         managed_code_bytes, PercentOfOatBytes(managed_code_bytes),
-                         managed_to_native_code_bytes, PercentOfOatBytes(managed_to_native_code_bytes),
-                         native_to_managed_code_bytes, PercentOfOatBytes(native_to_managed_code_bytes),
-                         class_initializer_code_bytes, PercentOfOatBytes(class_initializer_code_bytes),
-                         large_initializer_code_bytes, PercentOfOatBytes(large_initializer_code_bytes),
-                         large_method_code_bytes, PercentOfOatBytes(large_method_code_bytes))
+                         managed_code_bytes,
+                         PercentOfOatBytes(managed_code_bytes),
+                         managed_to_native_code_bytes,
+                         PercentOfOatBytes(managed_to_native_code_bytes),
+                         native_to_managed_code_bytes,
+                         PercentOfOatBytes(native_to_managed_code_bytes),
+                         class_initializer_code_bytes,
+                         PercentOfOatBytes(class_initializer_code_bytes),
+                         large_initializer_code_bytes,
+                         PercentOfOatBytes(large_initializer_code_bytes),
+                         large_method_code_bytes,
+                         PercentOfOatBytes(large_method_code_bytes))
             << "DexFile sizes:\n";
       for (const std::pair<std::string, size_t>& oat_dex_file_size : oat_dex_file_sizes) {
         os << StringPrintf("%s = %zd (%2.0f%% of oat file bytes)\n",
@@ -1386,7 +1417,8 @@
 
       os << StringPrintf("dex_instruction_bytes = %zd\n", dex_instruction_bytes)
          << StringPrintf("managed_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n\n",
-                         static_cast<double>(managed_code_bytes) / static_cast<double>(dex_instruction_bytes),
+                         static_cast<double>(managed_code_bytes) /
+                             static_cast<double>(dex_instruction_bytes),
                          static_cast<double>(managed_code_bytes_ignoring_deduplication) /
                              static_cast<double>(dex_instruction_bytes))
          << std::flush;
@@ -1406,7 +1438,6 @@
   };
   UniquePtr<OatDumper> oat_dumper_;
   std::ostream* os_;
-  const std::string image_filename_;
   gc::space::ImageSpace& image_space_;
   const ImageHeader& image_header_;
   bool dump_raw_mapping_table_;
@@ -1497,6 +1528,7 @@
   std::string boot_oat_option;
 
   // We are more like a compiler than a run-time. We don't want to execute code.
+  // TODO: Replace with NoopCompilerCallbacks.
   struct OatDumpCompilerCallbacks : CompilerCallbacks {
     virtual bool MethodVerified(verifier::MethodVerifier* /*verifier*/) { return true; }
     virtual void ClassRejected(ClassReference /*ref*/) { }
@@ -1532,8 +1564,8 @@
     fprintf(stderr, "Invalid image header %s\n", image_filename);
     return EXIT_FAILURE;
   }
-  ImageDumper image_dumper(os, image_filename, *image_space, image_header,
-    dump_raw_mapping_table, dump_raw_gc_map);
+  ImageDumper image_dumper(os, *image_space, image_header,
+                           dump_raw_mapping_table, dump_raw_gc_map);
   image_dumper.Dump();
   return EXIT_SUCCESS;
 }
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e5ca721..7e43994 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -581,7 +581,7 @@
   argv.push_back(oat_fd_option);
   argv.push_back(oat_location_option);
   const std::vector<std::string>& compiler_options = Runtime::Current()->GetCompilerOptions();
-  for (size_t i = 0; compiler_options.size(); ++i) {
+  for (size_t i = 0; i < compiler_options.size(); ++i) {
     argv.push_back(compiler_options[i].c_str());
   }
 
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index ef40be8..63e0d42 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -485,9 +485,11 @@
     ThrowAbstractMethodError(method);
     return 0;
   } else {
+    DCHECK(!method->IsNative()) << PrettyMethod(method);
     const char* old_cause = self->StartAssertNoThreadSuspension("Building interpreter shadow frame");
     MethodHelper mh(method);
     const DexFile::CodeItem* code_item = mh.GetCodeItem();
+    DCHECK(code_item != nullptr) << PrettyMethod(method);
     uint16_t num_regs = code_item->registers_size_;
     void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
     ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, NULL,  // No last shadow coming from quick.
@@ -507,7 +509,7 @@
       // Ensure static method's class is initialized.
       SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass());
       if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) {
-        DCHECK(Thread::Current()->IsExceptionPending());
+        DCHECK(Thread::Current()->IsExceptionPending()) << PrettyMethod(method);
         self->PopManagedStackFragment(fragment);
         return 0;
       }
@@ -766,7 +768,8 @@
   const void* code = NULL;
   if (LIKELY(!thread->IsExceptionPending())) {
     // Incompatible class change should have been handled in resolve method.
-    CHECK(!called->CheckIncompatibleClassChange(invoke_type));
+    CHECK(!called->CheckIncompatibleClassChange(invoke_type))
+        << PrettyMethod(called) << " " << invoke_type;
     if (virtual_or_interface) {
       // Refine called method based on receiver.
       CHECK(receiver != nullptr) << invoke_type;
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 98d4eef..8426fab 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -87,7 +87,7 @@
   }
 
   const std::vector<std::string>& compiler_options = Runtime::Current()->GetImageCompilerOptions();
-  for (size_t i = 0; compiler_options.size(); ++i) {
+  for (size_t i = 0; i < compiler_options.size(); ++i) {
     arg_vector.push_back(compiler_options[i].c_str());
   }
 
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 765074a..b6f36b6 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -186,10 +186,12 @@
   profile_clock_source_ = kDefaultProfilerClockSource;
 
   for (size_t i = 0; i < options.size(); ++i) {
-    const std::string option(options[i].first);
     if (true && options[0].first == "-Xzygote") {
-      LOG(INFO) << "option[" << i << "]=" << option;
+      LOG(INFO) << "option[" << i << "]=" << options[i].first;
     }
+  }
+  for (size_t i = 0; i < options.size(); ++i) {
+    const std::string option(options[i].first);
     if (StartsWith(option, "-help")) {
       Usage(nullptr);
       return false;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7546729..de06fb8 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -490,6 +490,9 @@
   default_stack_size_ = options->stack_size_;
   stack_trace_file_ = options->stack_trace_file_;
 
+  compiler_options_ = options->compiler_options_;
+  image_compiler_options_ = options->image_compiler_options_;
+
   max_spins_before_thin_lock_inflation_ = options->max_spins_before_thin_lock_inflation_;
 
   monitor_list_ = new MonitorList;