Use original dex file for retransformation.
The spec requires us to pass the dex file as it appeared before any
retransformation-capable agents had modified it to the
ClassFileLoadHooks when RetransformClasses is called. We do this by
saving the initial dex file bytes into the class as a byte[].
Bug: 32369916
Test: mma -j40 test-art-host
Change-Id: Ic6af3738cd2a831e91ba1144f502fa58b3c333e4
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index 2809cb6..af4fb71 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -47,6 +47,7 @@
#include "mem_map.h"
#include "mirror/array.h"
#include "mirror/class-inl.h"
+#include "mirror/class_ext.h"
#include "mirror/class_loader-inl.h"
#include "mirror/string-inl.h"
#include "oat_file.h"
@@ -138,28 +139,41 @@
return OK;
}
-// TODO Implement this for real once transformed dex data is actually saved.
+static jvmtiError CopyDataIntoJvmtiBuffer(ArtJvmTiEnv* env,
+ const unsigned char* source,
+ jint len,
+ /*out*/unsigned char** dest) {
+ jvmtiError res = env->Allocate(len, dest);
+ if (res != OK) {
+ return res;
+ }
+ memcpy(reinterpret_cast<void*>(*dest),
+ reinterpret_cast<const void*>(source),
+ len);
+ return OK;
+}
+
jvmtiError Transformer::GetDexDataForRetransformation(ArtJvmTiEnv* env,
art::Handle<art::mirror::Class> klass,
/*out*/jint* dex_data_len,
/*out*/unsigned char** dex_data) {
+ art::StackHandleScope<2> 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()));
+ 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);
+ }
+ }
// TODO De-quicken the dex file before passing it to the agents.
LOG(WARNING) << "Dex file is not de-quickened yet! Quickened dex instructions might be present";
- LOG(WARNING) << "Caching of initial dex data is not yet performed! Dex data might have been "
- << "transformed by agent already";
const art::DexFile& dex = klass->GetDexFile();
*dex_data_len = static_cast<jint>(dex.Size());
- unsigned char* new_dex_data = nullptr;
- jvmtiError alloc_error = env->Allocate(*dex_data_len, &new_dex_data);
- if (alloc_error != OK) {
- return alloc_error;
- }
- // Copy the data into a temporary buffer.
- memcpy(reinterpret_cast<void*>(new_dex_data),
- reinterpret_cast<const void*>(dex.Begin()),
- *dex_data_len);
- *dex_data = new_dex_data;
- return OK;
+ return CopyDataIntoJvmtiBuffer(env, dex.Begin(), *dex_data_len, /*out*/dex_data);
}
// TODO Move this function somewhere more appropriate.