Implement Class.getDex.

Change-Id: Iefb1e21a364e3e3b9f32ffd6ba57b55cfaee8c3b
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 924953f..b47be1f 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -386,7 +386,44 @@
   }
 }
 
-DexFile::~DexFile() {}
+DexFile::~DexFile() {
+  if (dex_object_ != NULL) {
+    UNIMPLEMENTED(WARNING) << "leaked a global reference to an com.android.dex.Dex instance";
+  }
+}
+
+jobject DexFile::GetDexObject(JNIEnv* env) const {
+  MutexLock mu(dex_object_lock_);
+  if (dex_object_ != NULL) {
+    return dex_object_;
+  }
+
+  void* address = const_cast<void*>(reinterpret_cast<const void*>(base_));
+  jobject byte_buffer = env->NewDirectByteBuffer(address, length_);
+  if (byte_buffer == NULL) {
+    return NULL;
+  }
+
+  jclass c = env->FindClass("com/android/dex/Dex");
+  if (c == NULL) {
+    return NULL;
+  }
+
+  jmethodID mid = env->GetStaticMethodID(c, "create", "(Ljava/nio/ByteBuffer;)Lcom/android/dex/Dex;");
+  if (mid == NULL) {
+    return NULL;
+  }
+
+  jvalue args[1];
+  args[0].l = byte_buffer;
+  jobject local = env->CallStaticObjectMethodA(c, mid, args);
+  if (local == NULL) {
+    return NULL;
+  }
+
+  dex_object_ = env->NewGlobalRef(local);
+  return dex_object_;
+}
 
 bool DexFile::Init() {
   InitMembers();
diff --git a/src/dex_file.h b/src/dex_file.h
index 359825a..4ad701f 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -9,8 +9,10 @@
 
 #include "UniquePtr.h"
 #include "globals.h"
+#include "jni.h"
 #include "leb128.h"
 #include "logging.h"
+#include "mutex.h"
 #include "stringpiece.h"
 #include "strutil.h"
 #include "utils.h"
@@ -348,6 +350,10 @@
     return location_;
   }
 
+  // Returns a com.android.dex.Dex object corresponding to the mapped-in dex file.
+  // Used by managed code to implement annotations.
+  jobject GetDexObject(JNIEnv* env) const;
+
   const Header& GetHeader() const {
     CHECK(header_ != NULL);
     return *header_;
@@ -874,6 +880,8 @@
         length_(length),
         location_(location),
         closer_(closer),
+        dex_object_lock_("a dex_object_lock_"),
+        dex_object_(NULL),
         header_(0),
         string_ids_(0),
         type_ids_(0),
@@ -920,6 +928,10 @@
   // Helper object to free the underlying allocation.
   UniquePtr<Closer> closer_;
 
+  // A cached com.android.dex.Dex instance, possibly NULL. Use GetDexObject.
+  mutable Mutex dex_object_lock_;
+  mutable jobject dex_object_;
+
   // Points to the header section.
   const Header* header_;
 
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index 207b124..32941be 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -57,6 +57,17 @@
     return JNI_FALSE;
 }
 
+jobject Class_getDex(JNIEnv* env, jobject javaClass) {
+  Class* c = Decode<Class*>(env, javaClass);
+
+  DexCache* dex_cache = c->GetDexCache();
+  if (dex_cache == NULL) {
+    return NULL;
+  }
+
+  return Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache).GetDexObject(env);
+}
+
 jobject Class_getClassLoader(JNIEnv* env, jclass, jobject javaClass) {
   Class* c = Decode<Class*>(env, javaClass);
   Object* result = reinterpret_cast<Object*>(const_cast<ClassLoader*>(c->GetClassLoader()));
@@ -312,6 +323,7 @@
   //NATIVE_METHOD(Class, getDeclaredFields, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Field;"),
   //NATIVE_METHOD(Class, getDeclaredMethods, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Method;"),
   NATIVE_METHOD(Class, getDeclaringClass, "()Ljava/lang/Class;"),
+  NATIVE_METHOD(Class, getDex, "()Lcom/android/dex/Dex;"),
   //NATIVE_METHOD(Class, getInnerClassName, "()Ljava/lang/String;"),
   //NATIVE_METHOD(Class, getInterfaces, "()[Ljava/lang/Class;"),
   //NATIVE_METHOD(Class, getModifiers, "(Ljava/lang/Class;Z)I"),