Revert "Revert "Make original dex file be more deduplicated""

This reverts commit a7c04c4fe6623985ba2d0cca942d5e1e584f4358.

Reason for revert: Issue with target buildbots was fixed

Test: m clean && ./test.py --target -j8
Bug: 31455788

Change-Id: If00ef9433a9308810a40ea4e0d809987c934cef8
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 9f04e59..b421810 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -618,7 +618,7 @@
   ClassExtOffsets() : CheckOffsets<mirror::ClassExt>(false, "Ldalvik/system/ClassExt;") {
     addOffset(OFFSETOF_MEMBER(mirror::ClassExt, obsolete_dex_caches_), "obsoleteDexCaches");
     addOffset(OFFSETOF_MEMBER(mirror::ClassExt, obsolete_methods_), "obsoleteMethods");
-    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, original_dex_file_bytes_), "originalDexFile");
+    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, original_dex_file_), "originalDexFile");
     addOffset(OFFSETOF_MEMBER(mirror::ClassExt, verify_error_), "verifyError");
   }
 };
diff --git a/runtime/mirror/class_ext.cc b/runtime/mirror/class_ext.cc
index 5dc3aca..94e4b88 100644
--- a/runtime/mirror/class_ext.cc
+++ b/runtime/mirror/class_ext.cc
@@ -117,9 +117,9 @@
   }
 }
 
-void ClassExt::SetOriginalDexFileBytes(ObjPtr<ByteArray> bytes) {
+void ClassExt::SetOriginalDexFile(ObjPtr<Object> bytes) {
   DCHECK(!Runtime::Current()->IsActiveTransaction());
-  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ClassExt, original_dex_file_bytes_), bytes);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ClassExt, original_dex_file_), bytes);
 }
 
 void ClassExt::SetClass(ObjPtr<Class> dalvik_system_ClassExt) {
diff --git a/runtime/mirror/class_ext.h b/runtime/mirror/class_ext.h
index fac955a..708665d 100644
--- a/runtime/mirror/class_ext.h
+++ b/runtime/mirror/class_ext.h
@@ -60,11 +60,11 @@
         OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_methods_));
   }
 
-  ByteArray* GetOriginalDexFileBytes() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return GetFieldObject<ByteArray>(OFFSET_OF_OBJECT_MEMBER(ClassExt, original_dex_file_bytes_));
+  Object* GetOriginalDexFile() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return GetFieldObject<Object>(OFFSET_OF_OBJECT_MEMBER(ClassExt, original_dex_file_));
   }
 
-  void SetOriginalDexFileBytes(ObjPtr<ByteArray> bytes) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetOriginalDexFile(ObjPtr<Object> bytes) REQUIRES_SHARED(Locks::mutator_lock_);
 
   void SetObsoleteArrays(ObjPtr<PointerArray> methods, ObjPtr<ObjectArray<DexCache>> dex_caches)
       REQUIRES_SHARED(Locks::mutator_lock_);
@@ -89,7 +89,7 @@
 
   HeapReference<PointerArray> obsolete_methods_;
 
-  HeapReference<ByteArray> original_dex_file_bytes_;
+  HeapReference<Object> original_dex_file_;
 
   // The saved verification error of this class.
   HeapReference<Object> verify_error_;
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index 2d1b25e..38fd1d4 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -259,7 +259,7 @@
       }
 
       // Actually set the ClassExt's original bytes once we have actually succeeded.
-      ext->SetOriginalDexFileBytes(arr.Get());
+      ext->SetOriginalDexFile(arr.Get());
       // Set the return values
       *final_class_def = &dex_file->GetClassDef(0);
       *final_dex_file = dex_file.release();
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 9c1d6ef..7faddfb 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -469,7 +469,7 @@
   result_ = result;
 }
 
-art::mirror::ByteArray* Redefiner::ClassRedefinition::AllocateOrGetOriginalDexFileBytes() {
+art::mirror::Object* Redefiner::ClassRedefinition::AllocateOrGetOriginalDexFile() {
   // If we have been specifically given a new set of bytes use that
   if (original_dex_file_.size() != 0) {
     return art::mirror::ByteArray::AllocateAndFill(
@@ -481,24 +481,21 @@
   // See if we already have one set.
   art::ObjPtr<art::mirror::ClassExt> ext(GetMirrorClass()->GetExtData());
   if (!ext.IsNull()) {
-    art::ObjPtr<art::mirror::ByteArray> old_original_bytes(ext->GetOriginalDexFileBytes());
-    if (!old_original_bytes.IsNull()) {
+    art::ObjPtr<art::mirror::Object> old_original_dex_file(ext->GetOriginalDexFile());
+    if (!old_original_dex_file.IsNull()) {
       // We do. Use it.
-      return old_original_bytes.Ptr();
+      return old_original_dex_file.Ptr();
     }
   }
 
-  // Copy the current dex_file
-  const art::DexFile& current_dex_file = GetMirrorClass()->GetDexFile();
+  // return the current dex_cache which has the dex file in it.
+  art::ObjPtr<art::mirror::DexCache> current_dex_cache(GetMirrorClass()->GetDexCache());
   // TODO Handle this or make it so it cannot happen.
-  if (current_dex_file.NumClassDefs() != 1) {
+  if (current_dex_cache->GetDexFile()->NumClassDefs() != 1) {
     LOG(WARNING) << "Current dex file has more than one class in it. Calling RetransformClasses "
                  << "on this class might fail if no transformations are applied to it!";
   }
-  return art::mirror::ByteArray::AllocateAndFill(
-      driver_->self_,
-      reinterpret_cast<const signed char*>(current_dex_file.Begin()),
-      current_dex_file.Size());
+  return current_dex_cache.Ptr();
 }
 
 struct CallbackCtx {
@@ -847,9 +844,9 @@
     return art::down_cast<art::mirror::Class*>(GetSlot(klass_index, kSlotMirrorClass));
   }
 
-  art::mirror::ByteArray* GetOriginalDexFileBytes(jint klass_index) const
+  art::mirror::Object* GetOriginalDexFile(jint klass_index) const
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
-    return art::down_cast<art::mirror::ByteArray*>(GetSlot(klass_index, kSlotOrigDexFile));
+    return art::down_cast<art::mirror::Object*>(GetSlot(klass_index, kSlotOrigDexFile));
   }
 
   void SetSourceClassLoader(jint klass_index, art::mirror::ClassLoader* loader)
@@ -872,7 +869,7 @@
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
     SetSlot(klass_index, kSlotMirrorClass, klass);
   }
-  void SetOriginalDexFileBytes(jint klass_index, art::mirror::ByteArray* bytes)
+  void SetOriginalDexFile(jint klass_index, art::mirror::Object* bytes)
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
     SetSlot(klass_index, kSlotOrigDexFile, bytes);
   }
@@ -985,9 +982,9 @@
   art::mirror::Class* GetMirrorClass() const REQUIRES_SHARED(art::Locks::mutator_lock_) {
     return holder_.GetMirrorClass(idx_);
   }
-  art::mirror::ByteArray* GetOriginalDexFileBytes() const
+  art::mirror::Object* GetOriginalDexFile() const
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
-    return holder_.GetOriginalDexFileBytes(idx_);
+    return holder_.GetOriginalDexFile(idx_);
   }
   int32_t GetIndex() const {
     return idx_;
@@ -1010,9 +1007,9 @@
   void SetMirrorClass(art::mirror::Class* klass) REQUIRES_SHARED(art::Locks::mutator_lock_) {
     holder_.SetMirrorClass(idx_, klass);
   }
-  void SetOriginalDexFileBytes(art::mirror::ByteArray* bytes)
+  void SetOriginalDexFile(art::mirror::Object* bytes)
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
-    holder_.SetOriginalDexFileBytes(idx_, bytes);
+    holder_.SetOriginalDexFile(idx_, bytes);
   }
 
  private:
@@ -1138,8 +1135,8 @@
   }
 
   // We won't always need to set this field.
-  cur_data->SetOriginalDexFileBytes(AllocateOrGetOriginalDexFileBytes());
-  if (cur_data->GetOriginalDexFileBytes() == nullptr) {
+  cur_data->SetOriginalDexFile(AllocateOrGetOriginalDexFile());
+  if (cur_data->GetOriginalDexFile() == nullptr) {
     driver_->self_->AssertPendingOOMException();
     driver_->self_->ClearException();
     RecordFailure(ERR(OUT_OF_MEMORY), "Unable to allocate array for original dex file");
@@ -1285,7 +1282,7 @@
     art::mirror::Class* klass = data.GetMirrorClass();
     // TODO Rewrite so we don't do a stack walk for each and every class.
     redef.FindAndAllocateObsoleteMethods(klass);
-    redef.UpdateClass(klass, data.GetNewDexCache(), data.GetOriginalDexFileBytes());
+    redef.UpdateClass(klass, data.GetNewDexCache(), data.GetOriginalDexFile());
   }
   // TODO We should check for if any of the redefined methods are intrinsic methods here and, if any
   // are, force a full-world deoptimization before finishing redefinition. If we don't do this then
@@ -1365,7 +1362,7 @@
 void Redefiner::ClassRedefinition::UpdateClass(
     art::ObjPtr<art::mirror::Class> mclass,
     art::ObjPtr<art::mirror::DexCache> new_dex_cache,
-    art::ObjPtr<art::mirror::ByteArray> original_dex_file) {
+    art::ObjPtr<art::mirror::Object> original_dex_file) {
   DCHECK_EQ(dex_file_->NumClassDefs(), 1u);
   const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(0);
   UpdateMethods(mclass, new_dex_cache, class_def);
@@ -1379,7 +1376,7 @@
   mclass->SetDexTypeIndex(dex_file_->GetIndexForTypeId(*dex_file_->FindTypeId(class_sig_.c_str())));
   art::ObjPtr<art::mirror::ClassExt> ext(mclass->GetExtData());
   CHECK(!ext.IsNull());
-  ext->SetOriginalDexFileBytes(original_dex_file);
+  ext->SetOriginalDexFile(original_dex_file);
 }
 
 // This function does all (java) allocations we need to do for the Class being redefined.
diff --git a/runtime/openjdkjvmti/ti_redefine.h b/runtime/openjdkjvmti/ti_redefine.h
index 4313a94..6c09d46 100644
--- a/runtime/openjdkjvmti/ti_redefine.h
+++ b/runtime/openjdkjvmti/ti_redefine.h
@@ -137,7 +137,7 @@
         REQUIRES_SHARED(art::Locks::mutator_lock_);
 
     // This may return nullptr with a OOME pending if allocation fails.
-    art::mirror::ByteArray* AllocateOrGetOriginalDexFileBytes()
+    art::mirror::Object* AllocateOrGetOriginalDexFile()
         REQUIRES_SHARED(art::Locks::mutator_lock_);
 
     void RecordFailure(jvmtiError e, const std::string& err) {
@@ -196,7 +196,7 @@
 
     void UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
                      art::ObjPtr<art::mirror::DexCache> new_dex_cache,
-                     art::ObjPtr<art::mirror::ByteArray> original_dex_file)
+                     art::ObjPtr<art::mirror::Object> original_dex_file)
         REQUIRES(art::Locks::mutator_lock_);
 
     void ReleaseDexFile() REQUIRES_SHARED(art::Locks::mutator_lock_);
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index bd52cbb..06aecba 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -150,16 +150,27 @@
                                                       art::Handle<art::mirror::Class> klass,
                                                       /*out*/jint* dex_data_len,
                                                       /*out*/unsigned char** dex_data) {
-  art::StackHandleScope<2> hs(art::Thread::Current());
+  art::StackHandleScope<3> hs(art::Thread::Current());
   art::Handle<art::mirror::ClassExt> ext(hs.NewHandle(klass->GetExtData()));
   if (!ext.IsNull()) {
-    art::Handle<art::mirror::ByteArray> orig_dex(hs.NewHandle(ext->GetOriginalDexFileBytes()));
+    art::Handle<art::mirror::Object> orig_dex(hs.NewHandle(ext->GetOriginalDexFile()));
     if (!orig_dex.IsNull()) {
-      *dex_data_len = static_cast<jint>(orig_dex->GetLength());
-      return CopyDataIntoJvmtiBuffer(env,
-                                     reinterpret_cast<const unsigned char*>(orig_dex->GetData()),
-                                     *dex_data_len,
-                                     /*out*/dex_data);
+      if (orig_dex->IsArrayInstance()) {
+        DCHECK(orig_dex->GetClass()->GetComponentType()->IsPrimitiveByte());
+        art::Handle<art::mirror::ByteArray> orig_dex_bytes(
+            hs.NewHandle(art::down_cast<art::mirror::ByteArray*>(orig_dex->AsArray())));
+        *dex_data_len = static_cast<jint>(orig_dex_bytes->GetLength());
+        return CopyDataIntoJvmtiBuffer(
+            env,
+            reinterpret_cast<const unsigned char*>(orig_dex_bytes->GetData()),
+            *dex_data_len,
+            /*out*/dex_data);
+      } else {
+        DCHECK(orig_dex->IsDexCache());
+        const art::DexFile* dex_file = orig_dex->AsDexCache()->GetDexFile();
+        *dex_data_len = static_cast<jint>(dex_file->Size());
+        return CopyDataIntoJvmtiBuffer(env, dex_file->Begin(), dex_file->Size(), /*out*/dex_data);
+      }
     }
   }
   // TODO De-quicken the dex file before passing it to the agents.
diff --git a/test/981-dedup-original-dex/expected.txt b/test/981-dedup-original-dex/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/981-dedup-original-dex/expected.txt
diff --git a/test/981-dedup-original-dex/info.txt b/test/981-dedup-original-dex/info.txt
new file mode 100644
index 0000000..62696e0
--- /dev/null
+++ b/test/981-dedup-original-dex/info.txt
@@ -0,0 +1,4 @@
+Tests basic functions in the jvmti plugin.
+
+This checks that we do not needlessly duplicate the contents of retransformed
+classes original dex files.
diff --git a/test/981-dedup-original-dex/run b/test/981-dedup-original-dex/run
new file mode 100755
index 0000000..e92b873
--- /dev/null
+++ b/test/981-dedup-original-dex/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+./default-run "$@" --jvmti
diff --git a/test/981-dedup-original-dex/src/Main.java b/test/981-dedup-original-dex/src/Main.java
new file mode 100644
index 0000000..cd3f007
--- /dev/null
+++ b/test/981-dedup-original-dex/src/Main.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Field;
+import java.util.Base64;
+
+import dalvik.system.ClassExt;
+
+public class Main {
+
+  /**
+   * base64 encoded class/dex file for
+   * class Transform {
+   *   public void sayHi() {
+   *    System.out.println("Goodbye");
+   *   }
+   * }
+   */
+  private static final byte[] DEX_BYTES_1 = Base64.getDecoder().decode(
+    "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
+    "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
+    "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
+    "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+    "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
+    "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
+    "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
+    "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
+    "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" +
+    "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
+    "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
+    "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
+    "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
+
+  /**
+   * base64 encoded class/dex file for
+   * class Transform2 {
+   *   public void sayHi() {
+   *    System.out.println("Goodbye2");
+   *   }
+   * }
+   */
+  private static final byte[] DEX_BYTES_2 = Base64.getDecoder().decode(
+    "ZGV4CjAzNQAjXDED2iflQ3NXbPtBRVjQVMqoDU9nDz/QAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" +
+    "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" +
+    "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" +
+    "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+    "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" +
+    "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" +
+    "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTIADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJp" +
+    "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" +
+    "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMzAA" +
+    "A291dAAHcHJpbnRsbgAFc2F5SGkAAQAHDgADAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" +
+    "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" +
+    "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" +
+    "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA");
+
+  public static void main(String[] args) {
+    try {
+      doTest();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  private static void assertSame(Object a, Object b) throws Exception {
+    if (a != b) {
+      throw new AssertionError("'" + (a != null ? a.toString() : "null") + "' is not the same as " +
+                               "'" + (b != null ? b.toString() : "null") + "'");
+    }
+  }
+
+  private static Object getObjectField(Object o, String name) throws Exception {
+    return getObjectField(o, o.getClass(), name);
+  }
+
+  private static Object getObjectField(Object o, Class<?> type, String name) throws Exception {
+    Field f = type.getDeclaredField(name);
+    f.setAccessible(true);
+    return f.get(o);
+  }
+
+  private static Object getOriginalDexFile(Class<?> k) throws Exception {
+    ClassExt ext_data_object = (ClassExt) getObjectField(k, "extData");
+    if (ext_data_object == null) {
+      return null;
+    }
+
+    return getObjectField(ext_data_object, "originalDexFile");
+  }
+
+  public static void doTest() throws Exception {
+    // Make sure both of these are loaded prior to transformations being added so they have the same
+    // original dex files.
+    Transform t1 = new Transform();
+    Transform2 t2 = new Transform2();
+
+    assertSame(null, getOriginalDexFile(t1.getClass()));
+    assertSame(null, getOriginalDexFile(t2.getClass()));
+    assertSame(null, getOriginalDexFile(Main.class));
+
+    addCommonTransformationResult("Transform", new byte[0], DEX_BYTES_1);
+    addCommonTransformationResult("Transform2", new byte[0], DEX_BYTES_2);
+    enableCommonRetransformation(true);
+    doCommonClassRetransformation(Transform.class, Transform2.class);
+
+    assertSame(getOriginalDexFile(t1.getClass()), getOriginalDexFile(t2.getClass()));
+    assertSame(null, getOriginalDexFile(Main.class));
+    // Make sure that the original dex file is a DexCache object.
+    assertSame(getOriginalDexFile(t1.getClass()).getClass(), Class.forName("java.lang.DexCache"));
+
+    // Check that we end up with a byte[] if we do a direct RedefineClasses
+    enableCommonRetransformation(false);
+    doCommonClassRedefinition(Transform.class, new byte[0], DEX_BYTES_1);
+    assertSame((new byte[0]).getClass(), getOriginalDexFile(t1.getClass()).getClass());
+  }
+
+  // Transforms the class
+  private static native void doCommonClassRetransformation(Class<?>... target);
+  private static native void doCommonClassRedefinition(Class<?> target,
+                                                       byte[] class_file,
+                                                       byte[] dex_file);
+  private static native void enableCommonRetransformation(boolean enable);
+  private static native void addCommonTransformationResult(String target_name,
+                                                           byte[] class_bytes,
+                                                           byte[] dex_bytes);
+}
diff --git a/test/981-dedup-original-dex/src/Transform.java b/test/981-dedup-original-dex/src/Transform.java
new file mode 100644
index 0000000..3c97907
--- /dev/null
+++ b/test/981-dedup-original-dex/src/Transform.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class Transform {
+  public void sayHi() {
+    System.out.println("hello");
+  }
+}
diff --git a/test/981-dedup-original-dex/src/Transform2.java b/test/981-dedup-original-dex/src/Transform2.java
new file mode 100644
index 0000000..eb22842
--- /dev/null
+++ b/test/981-dedup-original-dex/src/Transform2.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class Transform2 {
+  public void sayHi() {
+    System.out.println("hello2");
+  }
+}
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index fddae3a..8cb14bd 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -121,6 +121,7 @@
   { "943-private-recursive-jit", common_redefine::OnLoad, nullptr },
   { "944-transform-classloaders", common_redefine::OnLoad, nullptr },
   { "945-obsolete-native", common_redefine::OnLoad, nullptr },
+  { "981-dedup-original-dex", common_retransform::OnLoad, nullptr },
 };
 
 static AgentLib* FindAgent(char* name) {