diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/class_linker.cc | 21 | ||||
-rw-r--r-- | runtime/class_linker.h | 17 | ||||
-rw-r--r-- | runtime/runtime_callbacks.cc | 30 | ||||
-rw-r--r-- | runtime/runtime_callbacks.h | 11 | ||||
-rw-r--r-- | runtime/runtime_callbacks_test.cc | 26 |
5 files changed, 99 insertions, 6 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 14918df4d5..ddb324536f 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -2626,13 +2626,26 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, self->AssertPendingOOMException(); return nullptr; } - ObjPtr<mirror::DexCache> dex_cache = RegisterDexFile(dex_file, class_loader.Get()); + // Get the real dex file. This will return the input if there aren't any callbacks or they do + // nothing. + DexFile const* new_dex_file = nullptr; + DexFile::ClassDef const* new_class_def = nullptr; + // TODO We should ideally figure out some way to move this after we get a lock on the klass so it + // will only be called once. + Runtime::Current()->GetRuntimeCallbacks()->ClassPreDefine(descriptor, + klass, + class_loader, + dex_file, + dex_class_def, + &new_dex_file, + &new_class_def); + ObjPtr<mirror::DexCache> dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get()); if (dex_cache == nullptr) { self->AssertPendingOOMException(); return nullptr; } klass->SetDexCache(dex_cache); - SetupClass(dex_file, dex_class_def, klass, class_loader.Get()); + SetupClass(*new_dex_file, *new_class_def, klass, class_loader.Get()); // Mark the string class by setting its access flag. if (UNLIKELY(!init_done_)) { @@ -2658,7 +2671,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, // end up allocating unfree-able linear alloc resources and then lose the race condition. The // other reason is that the field roots are only visited from the class table. So we need to be // inserted before we allocate / fill in these fields. - LoadClass(self, dex_file, dex_class_def, klass); + LoadClass(self, *new_dex_file, *new_class_def, klass); if (self->IsExceptionPending()) { VLOG(class_linker) << self->GetException()->Dump(); // An exception occured during load, set status to erroneous while holding klass' lock in case @@ -2671,7 +2684,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, // Finish loading (if necessary) by finding parents CHECK(!klass->IsLoaded()); - if (!LoadSuperAndInterfaces(klass, dex_file)) { + if (!LoadSuperAndInterfaces(klass, *new_dex_file)) { // Loading failed. if (!klass->IsErroneous()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 8da979b36f..d3bb58dc33 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -1199,6 +1199,23 @@ class ClassLoadCallback { public: virtual ~ClassLoadCallback() {} + // If set we will replace initial_class_def & initial_dex_file with the final versions. The + // callback author is responsible for ensuring these are allocated in such a way they can be + // cleaned up if another transformation occurs. Note that both must be set or null/unchanged on + // return. + // Note: the class may be temporary, in which case a following ClassPrepare event will be a + // different object. It is the listener's responsibility to handle this. + // Note: This callback is rarely useful so a default implementation has been given that does + // nothing. + virtual void ClassPreDefine(const char* descriptor ATTRIBUTE_UNUSED, + Handle<mirror::Class> klass ATTRIBUTE_UNUSED, + Handle<mirror::ClassLoader> class_loader ATTRIBUTE_UNUSED, + const DexFile& initial_dex_file ATTRIBUTE_UNUSED, + const DexFile::ClassDef& initial_class_def ATTRIBUTE_UNUSED, + /*out*/DexFile const** final_dex_file ATTRIBUTE_UNUSED, + /*out*/DexFile::ClassDef const** final_dex_cache ATTRIBUTE_UNUSED) + REQUIRES_SHARED(Locks::mutator_lock_) {} + // A class has been loaded. // Note: the class may be temporary, in which case a following ClassPrepare event will be a // different object. It is the listener's responsibility to handle this. diff --git a/runtime/runtime_callbacks.cc b/runtime/runtime_callbacks.cc index 7b15a4f1b5..25324b52d1 100644 --- a/runtime/runtime_callbacks.cc +++ b/runtime/runtime_callbacks.cc @@ -67,6 +67,36 @@ void RuntimeCallbacks::ClassLoad(Handle<mirror::Class> klass) { } } +void RuntimeCallbacks::ClassPreDefine(const char* descriptor, + Handle<mirror::Class> temp_class, + Handle<mirror::ClassLoader> loader, + const DexFile& initial_dex_file, + const DexFile::ClassDef& initial_class_def, + /*out*/DexFile const** final_dex_file, + /*out*/DexFile::ClassDef const** final_class_def) { + DexFile const* current_dex_file = &initial_dex_file; + DexFile::ClassDef const* current_class_def = &initial_class_def; + for (ClassLoadCallback* cb : class_callbacks_) { + DexFile const* new_dex_file = nullptr; + DexFile::ClassDef const* new_class_def = nullptr; + cb->ClassPreDefine(descriptor, + temp_class, + loader, + *current_dex_file, + *current_class_def, + &new_dex_file, + &new_class_def); + if ((new_dex_file != nullptr && new_dex_file != current_dex_file) || + (new_class_def != nullptr && new_class_def != current_class_def)) { + DCHECK(new_dex_file != nullptr && new_class_def != nullptr); + current_dex_file = new_dex_file; + current_class_def = new_class_def; + } + } + *final_dex_file = current_dex_file; + *final_class_def = current_class_def; +} + void RuntimeCallbacks::ClassPrepare(Handle<mirror::Class> temp_klass, Handle<mirror::Class> klass) { for (ClassLoadCallback* cb : class_callbacks_) { cb->ClassPrepare(temp_klass, klass); diff --git a/runtime/runtime_callbacks.h b/runtime/runtime_callbacks.h index e580e7875e..d321254e17 100644 --- a/runtime/runtime_callbacks.h +++ b/runtime/runtime_callbacks.h @@ -21,12 +21,14 @@ #include "base/macros.h" #include "base/mutex.h" +#include "dex_file.h" #include "handle.h" namespace art { namespace mirror { class Class; +class ClassLoader; } // namespace mirror class ClassLoadCallback; @@ -99,6 +101,15 @@ class RuntimeCallbacks { void NextRuntimePhase(RuntimePhaseCallback::RuntimePhase phase) REQUIRES_SHARED(Locks::mutator_lock_); + void ClassPreDefine(const char* descriptor, + Handle<mirror::Class> temp_class, + Handle<mirror::ClassLoader> loader, + const DexFile& initial_dex_file, + const DexFile::ClassDef& initial_class_def, + /*out*/DexFile const** final_dex_file, + /*out*/DexFile::ClassDef const** final_class_def) + REQUIRES_SHARED(Locks::mutator_lock_); + private: std::vector<ThreadLifecycleCallback*> thread_callbacks_ GUARDED_BY(Locks::mutator_lock_); diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc index 8974b595de..66eb2ec3b1 100644 --- a/runtime/runtime_callbacks_test.cc +++ b/runtime/runtime_callbacks_test.cc @@ -249,6 +249,21 @@ class ClassLoadCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest { } struct Callback : public ClassLoadCallback { + virtual void ClassPreDefine(const char* descriptor, + Handle<mirror::Class> klass ATTRIBUTE_UNUSED, + Handle<mirror::ClassLoader> class_loader ATTRIBUTE_UNUSED, + const DexFile& initial_dex_file, + const DexFile::ClassDef& initial_class_def ATTRIBUTE_UNUSED, + /*out*/DexFile const** final_dex_file ATTRIBUTE_UNUSED, + /*out*/DexFile::ClassDef const** final_dex_cache ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { + std::string location(initial_dex_file.GetLocation()); + std::string event = + std::string("PreDefine:") + descriptor + " <" + + location.substr(location.rfind("/") + 1, location.size()) + ">"; + data.push_back(event); + } + void ClassLoad(Handle<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { std::string tmp; std::string event = std::string("Load:") + klass->GetDescriptor(&tmp); @@ -281,14 +296,21 @@ TEST_F(ClassLoadCallbackRuntimeCallbacksTest, ClassLoadCallback) { hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_y, class_loader))); ASSERT_TRUE(h_Y.Get() != nullptr); - bool expect1 = Expect({ "Load:LX;", "Prepare:LX;[LX;]", "Load:LY;", "Prepare:LY;[LY;]" }); + bool expect1 = Expect({ "PreDefine:LY; <art-gtest-XandY.jar>", + "PreDefine:LX; <art-gtest-XandY.jar>", + "Load:LX;", + "Prepare:LX;[LX;]", + "Load:LY;", + "Prepare:LY;[LY;]" }); EXPECT_TRUE(expect1); cb_.data.clear(); ASSERT_TRUE(class_linker_->EnsureInitialized(Thread::Current(), h_Y, true, true)); - bool expect2 = Expect({ "Load:LY$Z;", "Prepare:LY$Z;[LY$Z;]" }); + bool expect2 = Expect({ "PreDefine:LY$Z; <art-gtest-XandY.jar>", + "Load:LY$Z;", + "Prepare:LY$Z;[LY$Z;]" }); EXPECT_TRUE(expect2); } |