Record Class::Status information in oat file

Change-Id: I328de86a89c7d84a211b3aed3d42b8c92c1f3464
diff --git a/src/compiled_class.h b/src/compiled_class.h
new file mode 100644
index 0000000..98f0d9f
--- /dev/null
+++ b/src/compiled_class.h
@@ -0,0 +1,24 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_COMPILED_CLASS_H_
+#define ART_SRC_COMPILED_CLASS_H_
+
+#include "object.h"
+
+namespace art {
+
+class CompiledClass {
+ public:
+  CompiledClass(Class::Status status) : status_(status) {};
+  ~CompiledClass() {};
+  Class::Status GetStatus() const {
+    return status_;
+  }
+ private:
+  const Class::Status status_;
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_COMPILED_CLASS_H_
+
diff --git a/src/compiled_method.h b/src/compiled_method.h
index b09a762..4b5a78b 100644
--- a/src/compiled_method.h
+++ b/src/compiled_method.h
@@ -12,7 +12,7 @@
 
 class CompiledMethod {
  public:
-  // Create an CompiledMethod from the oatCompileMethod
+  // Create a CompiledMethod from the oatCompileMethod
   CompiledMethod(InstructionSet instruction_set,
                  std::vector<short>& code,
                  const size_t frame_size_in_bytes,
@@ -21,7 +21,7 @@
                  std::vector<uint32_t>& mapping_table,
                  std::vector<uint16_t>& vmap_table);
 
-  // Create an CompiledMethod from the JniCompiler
+  // Create a CompiledMethod from the JniCompiler
   CompiledMethod(InstructionSet instruction_set,
                  std::vector<uint8_t>& code,
                  const size_t frame_size_in_bytes,
diff --git a/src/compiler.cc b/src/compiler.cc
index e01ab74..88e156d 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -50,6 +50,7 @@
 }
 
 Compiler::~Compiler() {
+  STLDeleteValues(&compiled_classes_);
   STLDeleteValues(&compiled_methods_);
   STLDeleteValues(&compiled_invoke_stubs_);
 }
@@ -323,9 +324,20 @@
     Class* klass = class_linker->FindClass(descriptor, class_loader);
     if (klass != NULL) {
       class_linker->EnsureInitialized(klass, false);
+      // record the final class status if necessary
+      Class::Status status = klass->GetStatus();
+      ClassReference ref(&dex_file, class_def_index);
+      CompiledClass* compiled_class = GetCompiledClass(ref);
+      if (compiled_class == NULL) {
+        compiled_class = new CompiledClass(status);
+        compiled_classes_[ref] = compiled_class;
+      } else {
+        DCHECK_EQ(status, compiled_class->GetStatus());
+      }
     }
     // clear any class not found or verification exceptions
     Thread::Current()->ClearException();
+
   }
 
   DexCache* dex_cache = class_linker->FindDexCache(dex_file);
@@ -404,13 +416,9 @@
 
   if (compiled_method != NULL) {
     MethodReference ref(&dex_file, method_idx);
-    CHECK(compiled_methods_.find(ref) == compiled_methods_.end())
-        << PrettyMethod(method_idx, dex_file);
+    CHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
     compiled_methods_[ref] = compiled_method;
-    DCHECK(compiled_methods_.find(ref) != compiled_methods_.end())
-        << PrettyMethod(method_idx, dex_file);
-    DCHECK(GetCompiledMethod(ref) != NULL)
-        << PrettyMethod(method_idx, dex_file);
+    DCHECK(GetCompiledMethod(ref) != NULL) << PrettyMethod(method_idx, dex_file);
   }
 
   const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
@@ -455,6 +463,15 @@
   compiled_invoke_stubs_[key] = compiled_invoke_stub;
 }
 
+CompiledClass* Compiler::GetCompiledClass(ClassReference ref) const {
+  ClassTable::const_iterator it = compiled_classes_.find(ref);
+  if (it == compiled_classes_.end()) {
+    return NULL;
+  }
+  CHECK(it->second != NULL);
+  return it->second;
+}
+
 CompiledMethod* Compiler::GetCompiledMethod(MethodReference ref) const {
   MethodTable::const_iterator it = compiled_methods_.find(ref);
   if (it == compiled_methods_.end()) {
diff --git a/src/compiler.h b/src/compiler.h
index f05f80b..f59587f 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -3,6 +3,7 @@
 #ifndef ART_SRC_COMPILER_H_
 #define ART_SRC_COMPILER_H_
 
+#include "compiled_class.h"
 #include "compiled_method.h"
 #include "constants.h"
 #include "dex_cache.h"
@@ -55,10 +56,14 @@
 
   static ByteArray* CreateJniDlysmLookupStub(InstructionSet instruction_set);
 
-  // A method is uniquely located by its DexFile and index into the method_id table of that dex file
-  typedef std::pair<const DexFile*, uint32_t> MethodReference;
+  // A class is uniquely located by its DexFile and the class_defs_ table index into that DexFile
+  typedef std::pair<const DexFile*, uint32_t> ClassReference;
+  CompiledClass* GetCompiledClass(ClassReference ref) const;
 
+  // A method is uniquely located by its DexFile and the method_ids_ table index into that DexFile
+  typedef std::pair<const DexFile*, uint32_t> MethodReference;
   CompiledMethod* GetCompiledMethod(MethodReference ref) const;
+
   const CompiledInvokeStub* FindInvokeStub(bool is_static, const char* shorty) const;
 
   // Callbacks from OAT/ART compiler to see what runtime checks must be generated
@@ -122,8 +127,25 @@
   InstructionSet instruction_set_;
   JniCompiler jni_compiler_;
 
+  struct ClassReferenceHash {
+    size_t operator()(const ClassReference& id) const {
+      size_t dex = reinterpret_cast<size_t>(id.first);
+      DCHECK_NE(dex, static_cast<size_t>(0));
+      dex += 33;  // dex is an aligned pointer, get some non-zero low bits
+      size_t idx = id.second;
+      if (idx == 0) {  // special case of a method index of 0
+        return dex * 5381;
+      } else {
+        return dex * idx;
+      }
+    }
+  };
+  typedef std::tr1::unordered_map<const ClassReference, CompiledClass*, ClassReferenceHash> ClassTable;
+  // All class references that this compiler has compiled
+  ClassTable compiled_classes_;
+
   struct MethodReferenceHash {
-    size_t operator()(const MethodReference id) const {
+    size_t operator()(const MethodReference& id) const {
       size_t dex = reinterpret_cast<size_t>(id.first);
       DCHECK_NE(dex, static_cast<size_t>(0));
       dex += 33;  // dex is an aligned pointer, get some non-zero low bits
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 4d6b4a5..646f1c5 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -166,12 +166,12 @@
                                 std::string dex_file_location,
                                 uint32_t dex_file_checksum,
                                 byte* dex_file_pointer,
-                                const uint32_t* methods_offsets_pointer)
+                                const uint32_t* oat_class_offsets_pointer)
     : oat_file_(oat_file),
       dex_file_location_(dex_file_location),
       dex_file_checksum_(dex_file_checksum),
       dex_file_pointer_(dex_file_pointer),
-      methods_offsets_pointer_(methods_offsets_pointer) {}
+      oat_class_offsets_pointer_(oat_class_offsets_pointer) {}
 
 OatFile::OatDexFile::~OatDexFile() {}
 
@@ -181,17 +181,31 @@
 }
 
 const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
-  uint32_t methods_offset = methods_offsets_pointer_[class_def_index];
-  const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
+  uint32_t oat_class_offset = oat_class_offsets_pointer_[class_def_index];
+
+  const byte* oat_class_pointer = oat_file_->GetBase() + oat_class_offset;
+  CHECK_LT(oat_class_pointer, oat_file_->GetLimit());
+  Class::Status status = *reinterpret_cast<const Class::Status*>(oat_class_pointer);
+
+  const byte* methods_pointer = oat_class_pointer + sizeof(status);
   CHECK_LT(methods_pointer, oat_file_->GetLimit());
-  return new OatClass(oat_file_, reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
+
+  return new OatClass(oat_file_,
+                      status,
+                      reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
 }
 
-OatFile::OatClass::OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer)
-    : oat_file_(oat_file), methods_pointer_(methods_pointer) {}
+OatFile::OatClass::OatClass(const OatFile* oat_file,
+                            Class::Status status,
+                            const OatMethodOffsets* methods_pointer)
+    : oat_file_(oat_file), status_(status), methods_pointer_(methods_pointer) {}
 
 OatFile::OatClass::~OatClass() {}
 
+Class::Status OatFile::OatClass::GetStatus() const {
+  return status_;
+}
+
 const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
   const OatMethodOffsets& oat_method_offsets = methods_pointer_[method_index];
   return OatMethod(
diff --git a/src/oat_file.h b/src/oat_file.h
index 5b05ad6..5c011fd 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -114,6 +114,8 @@
 
   class OatClass {
    public:
+    Class::Status GetStatus() const;
+
     // get the OatMethod entry based on its index into the class
     // defintion. direct methods come first, followed by virtual
     // methods. note that runtime created methods such as miranda
@@ -122,9 +124,12 @@
     ~OatClass();
 
    private:
-    OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer);
+    OatClass(const OatFile* oat_file,
+             Class::Status status,
+             const OatMethodOffsets* methods_pointer);
 
     const OatFile* oat_file_;
+    const Class::Status status_;
     const OatMethodOffsets* methods_pointer_;
 
     friend class OatDexFile;
@@ -149,13 +154,13 @@
                std::string dex_file_location,
                uint32_t dex_file_checksum,
                byte* dex_file_pointer,
-               const uint32_t* methods_offsets_pointer);
+               const uint32_t* oat_class_offsets_pointer);
 
     const OatFile* oat_file_;
     std::string dex_file_location_;
     uint32_t dex_file_checksum_;
     const byte* dex_file_pointer_;
-    const uint32_t* methods_offsets_pointer_;
+    const uint32_t* oat_class_offsets_pointer_;
 
     friend class OatFile;
     DISALLOW_COPY_AND_ASSIGN(OatDexFile);
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index fa27737..806ac71 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -96,7 +96,13 @@
         size_t num_virtual_methods = it.NumVirtualMethods();
         num_methods = num_direct_methods + num_virtual_methods;
       }
-      OatClass* oat_class = new OatClass(num_methods);
+
+      CompiledClass* compiled_class =
+          compiler_->GetCompiledClass(art::Compiler::MethodReference(dex_file, class_def_index));
+      Class::Status status =
+          (compiled_class != NULL) ? compiled_class->GetStatus() : Class::kStatusNotReady;
+
+      OatClass* oat_class = new OatClass(status, num_methods);
       oat_classes_.push_back(oat_class);
       offset += oat_class->SizeOf();
     }
@@ -656,20 +662,29 @@
   return true;
 }
 
-OatWriter::OatClass::OatClass(uint32_t methods_count) {
+OatWriter::OatClass::OatClass(Class::Status status, uint32_t methods_count) {
+  status_ = status;
   method_offsets_.resize(methods_count);
 }
 
 size_t OatWriter::OatClass::SizeOf() const {
-  return (sizeof(method_offsets_[0]) * method_offsets_.size());
+  return sizeof(status_)
+          + (sizeof(method_offsets_[0]) * method_offsets_.size());
 }
 
 void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
-  oat_header.UpdateChecksum(&method_offsets_[0], SizeOf());
+  oat_header.UpdateChecksum(&status_, sizeof(status_));
+  oat_header.UpdateChecksum(&method_offsets_[0],
+                            sizeof(method_offsets_[0]) * method_offsets_.size());
 }
 
 bool OatWriter::OatClass::Write(File* file) const {
-  if (!file->WriteFully(&method_offsets_[0], SizeOf())) {
+  if (!file->WriteFully(&status_, sizeof(status_))) {
+    PLOG(ERROR) << "Failed to write class status to " << file->name();
+    return false;
+  }
+  if (!file->WriteFully(&method_offsets_[0],
+                        sizeof(method_offsets_[0]) * method_offsets_.size())) {
     PLOG(ERROR) << "Failed to write method offsets to " << file->name();
     return false;
   }
diff --git a/src/oat_writer.h b/src/oat_writer.h
index a5de14e..6ae0f4e 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -109,12 +109,13 @@
 
   class OatClass {
    public:
-    explicit OatClass(uint32_t methods_count);
+    explicit OatClass(Class::Status status, uint32_t methods_count);
     size_t SizeOf() const;
     void UpdateChecksum(OatHeader& oat_header) const;
     bool Write(File* file) const;
 
     // data to write
+    Class::Status status_;
     std::vector<OatMethodOffsets> method_offsets_;
 
    private: