Eager verification GC maps are present in debug mode

Change-Id: Iaefc0bf937ae1476bcfb0aadd6a3e5e434e2d621
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 22f8a8a..3154a1b 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1798,6 +1798,29 @@
   }
 }
 
+#ifndef NDEBUG
+static void CheckMethodsHaveGcMaps(Class* klass) {
+  if (!Runtime::Current()->IsStarted()) {
+    return;
+  }
+  for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
+    Method* method = klass->GetDirectMethod(i);
+    if (!method->IsNative() && !method->IsAbstract()) {
+      CHECK(method->GetGcMap() != NULL) << PrettyMethod(method);
+    }
+  }
+  for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
+    Method* method = klass->GetVirtualMethod(i);
+    if (!method->IsNative() && !method->IsAbstract()) {
+      CHECK(method->GetGcMap() != NULL) << PrettyMethod(method);
+    }
+  }
+}
+#else
+static void CheckMethodsHaveGcMaps(Class* klass) {
+}
+#endif
+
 void ClassLinker::VerifyClass(Class* klass) {
   // TODO: assert that the monitor on the Class is held
   if (klass->IsVerified()) {
@@ -1813,6 +1836,8 @@
     // Make sure all classes referenced by catch blocks are resolved
     ResolveClassExceptionHandlerTypes(dex_file, klass);
     klass->SetStatus(Class::kStatusVerified);
+    // Sanity check that a verified class has GC maps on all methods
+    CheckMethodsHaveGcMaps(klass);
   } else {
     LOG(ERROR) << "Verification failed on class " << PrettyClass(klass);
     Thread* self = Thread::Current();
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 9690142..8b19727 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -80,12 +80,11 @@
 size_t OatWriter::InitOatClasses(size_t offset) {
   // create the OatClasses
   // calculate the offsets within OatDexFiles to OatClasses
-  size_t class_index = 0;
   for (size_t i = 0; i != dex_files_->size(); ++i) {
     const DexFile* dex_file = (*dex_files_)[i];
     for (size_t class_def_index = 0;
          class_def_index < dex_file->NumClassDefs();
-         class_def_index++, class_index++) {
+         class_def_index++) {
       oat_dex_files_[i]->methods_offsets_[class_def_index] = offset;
       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
       const byte* class_data = dex_file->GetClassData(class_def);
@@ -138,14 +137,14 @@
        class_def_index < dex_file.NumClassDefs();
        class_def_index++, oat_class_index++) {
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
-    offset = InitOatCodeClassDef(offset, oat_class_index, dex_file, class_def);
+    offset = InitOatCodeClassDef(offset, oat_class_index, class_def_index, dex_file, class_def);
     oat_classes_[oat_class_index]->UpdateChecksum(*oat_header_);
   }
   return offset;
 }
 
 size_t OatWriter::InitOatCodeClassDef(size_t offset,
-                                      size_t oat_class_index,
+                                      size_t oat_class_index, size_t class_def_index,
                                       const DexFile& dex_file,
                                       const DexFile::ClassDef& class_def) {
   const byte* class_data = dex_file.GetClassData(class_def);
@@ -167,15 +166,17 @@
   size_t class_def_method_index = 0;
   while (it.HasNextDirectMethod()) {
     bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
-    offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, is_static, true,
-                               it.GetMemberIndex(), &dex_file);
+    bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
+    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index, is_native,
+                               is_static, true, it.GetMemberIndex(), &dex_file);
     class_def_method_index++;
     it.Next();
   }
   while (it.HasNextVirtualMethod()) {
     CHECK_EQ(it.GetMemberAccessFlags() & kAccStatic, 0U);
-    offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, false, false,
-                               it.GetMemberIndex(), &dex_file);
+    bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
+    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index, is_native,
+                               false, false, it.GetMemberIndex(), &dex_file);
     class_def_method_index++;
     it.Next();
   }
@@ -183,9 +184,9 @@
   return offset;
 }
 
-size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
-                                    size_t class_def_method_index, bool is_static, bool is_direct,
-                                    uint32_t method_idx, const DexFile* dex_file) {
+size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t class_def_index,
+                                    size_t class_def_method_index, bool is_native, bool is_static,
+                                    bool is_direct, uint32_t method_idx, const DexFile* dex_file) {
   // derived from CompiledMethod if available
   uint32_t code_offset = 0;
   uint32_t frame_size_in_bytes = kStackAlignment;
@@ -264,6 +265,16 @@
     size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
     gc_map_offset = (gc_map_size == 0) ? 0 : offset;
 
+#ifndef NDEBUG
+    // We expect GC maps except when the class hasn't been verified or the method is native
+    CompiledClass* compiled_class =
+        compiler_->GetCompiledClass(art::Compiler::MethodReference(dex_file, class_def_index));
+    Class::Status status =
+        (compiled_class != NULL) ? compiled_class->GetStatus() : Class::kStatusNotReady;
+    CHECK(gc_map_size != 0 || is_native || status < Class::kStatusVerified)
+        << PrettyMethod(method_idx, *dex_file);
+#endif
+
     // Deduplicate GC maps
     std::map<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = gc_map_offsets_.find(&gc_map);
     if (gc_map_iter != gc_map_offsets_.end()) {
diff --git a/src/oat_writer.h b/src/oat_writer.h
index d1983a5..a9ea7ef 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -68,11 +68,12 @@
                             size_t& oat_class_index,
                             const DexFile& dex_file);
   size_t InitOatCodeClassDef(size_t offset,
-                             size_t oat_class_index,
+                             size_t oat_class_index, size_t class_def_index,
                              const DexFile& dex_file,
                              const DexFile::ClassDef& class_def);
-  size_t InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t class_def_method_index,
-                           bool is_static, bool is_direct, uint32_t method_idx, const DexFile*);
+  size_t InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t class_def_index,
+                           size_t class_def_method_index, bool is_native, bool is_static,
+                           bool is_direct, uint32_t method_idx, const DexFile*);
 
   bool Write(File* file);
   bool WriteTables(File* file);