summaryrefslogtreecommitdiff
path: root/openjdkjvmti/transform.cc
diff options
context:
space:
mode:
Diffstat (limited to 'openjdkjvmti/transform.cc')
-rw-r--r--openjdkjvmti/transform.cc239
1 files changed, 220 insertions, 19 deletions
diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc
index 3a5fcccf35..dc9f69a96a 100644
--- a/openjdkjvmti/transform.cc
+++ b/openjdkjvmti/transform.cc
@@ -29,6 +29,9 @@
* questions.
*/
+#include <stddef.h>
+#include <sys/types.h>
+
#include <unordered_map>
#include <unordered_set>
@@ -39,7 +42,9 @@
#include "class_linker.h"
#include "dex/dex_file.h"
#include "dex/dex_file_types.h"
+#include "dex/utf.h"
#include "events-inl.h"
+#include "fault_handler.h"
#include "gc_root-inl.h"
#include "globals.h"
#include "jni_env_ext-inl.h"
@@ -58,32 +63,228 @@
#include "thread_list.h"
#include "ti_redefine.h"
#include "transform.h"
-#include "utf.h"
#include "utils/dex_cache_arrays_layout-inl.h"
namespace openjdkjvmti {
+// A FaultHandler that will deal with initializing ClassDefinitions when they are actually needed.
+class TransformationFaultHandler FINAL : public art::FaultHandler {
+ public:
+ explicit TransformationFaultHandler(art::FaultManager* manager)
+ : art::FaultHandler(manager),
+ uninitialized_class_definitions_lock_("JVMTI Initialized class definitions lock",
+ art::LockLevel::kSignalHandlingLock),
+ class_definition_initialized_cond_("JVMTI Initialized class definitions condition",
+ uninitialized_class_definitions_lock_) {
+ manager->AddHandler(this, /* generated_code */ false);
+ }
+
+ ~TransformationFaultHandler() {
+ art::MutexLock mu(art::Thread::Current(), uninitialized_class_definitions_lock_);
+ uninitialized_class_definitions_.clear();
+ }
+
+ bool Action(int sig, siginfo_t* siginfo, void* context ATTRIBUTE_UNUSED) OVERRIDE {
+ DCHECK_EQ(sig, SIGSEGV);
+ art::Thread* self = art::Thread::Current();
+ if (UNLIKELY(uninitialized_class_definitions_lock_.IsExclusiveHeld(self))) {
+ if (self != nullptr) {
+ LOG(FATAL) << "Recursive call into Transformation fault handler!";
+ UNREACHABLE();
+ } else {
+ LOG(ERROR) << "Possible deadlock due to recursive signal delivery of segv.";
+ }
+ }
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(siginfo->si_addr);
+ ArtClassDefinition* res = nullptr;
+
+ {
+ // NB Technically using a mutex and condition variables here is non-posix compliant but
+ // everything should be fine since both glibc and bionic implementations of mutexs and
+ // condition variables work fine so long as the thread was not interrupted during a
+ // lock/unlock (which it wasn't) on all architectures we care about.
+ art::MutexLock mu(self, uninitialized_class_definitions_lock_);
+ auto it = std::find_if(uninitialized_class_definitions_.begin(),
+ uninitialized_class_definitions_.end(),
+ [&](const auto op) { return op->ContainsAddress(ptr); });
+ if (it != uninitialized_class_definitions_.end()) {
+ res = *it;
+ // Remove the class definition.
+ uninitialized_class_definitions_.erase(it);
+ // Put it in the initializing list
+ initializing_class_definitions_.push_back(res);
+ } else {
+ // Wait for the ptr to be initialized (if it is currently initializing).
+ while (DefinitionIsInitializing(ptr)) {
+ WaitForClassInitializationToFinish();
+ }
+ // Return true (continue with user code) if we find that the definition has been
+ // initialized. Return false (continue on to next signal handler) if the definition is not
+ // initialized or found.
+ return std::find_if(initialized_class_definitions_.begin(),
+ initialized_class_definitions_.end(),
+ [&](const auto op) { return op->ContainsAddress(ptr); }) !=
+ uninitialized_class_definitions_.end();
+ }
+ }
+
+ if (LIKELY(self != nullptr)) {
+ CHECK_EQ(self->GetState(), art::ThreadState::kNative)
+ << "Transformation fault handler occurred outside of native mode";
+ }
+
+ VLOG(signals) << "Lazy initialization of dex file for transformation of " << res->GetName()
+ << " during SEGV";
+ res->InitializeMemory();
+
+ {
+ art::MutexLock mu(self, uninitialized_class_definitions_lock_);
+ // Move to initialized state and notify waiters.
+ initializing_class_definitions_.erase(std::find(initializing_class_definitions_.begin(),
+ initializing_class_definitions_.end(),
+ res));
+ initialized_class_definitions_.push_back(res);
+ class_definition_initialized_cond_.Broadcast(self);
+ }
+
+ return true;
+ }
+
+ void RemoveDefinition(ArtClassDefinition* def) REQUIRES(!uninitialized_class_definitions_lock_) {
+ art::MutexLock mu(art::Thread::Current(), uninitialized_class_definitions_lock_);
+ auto it = std::find(uninitialized_class_definitions_.begin(),
+ uninitialized_class_definitions_.end(),
+ def);
+ if (it != uninitialized_class_definitions_.end()) {
+ uninitialized_class_definitions_.erase(it);
+ return;
+ }
+ while (std::find(initializing_class_definitions_.begin(),
+ initializing_class_definitions_.end(),
+ def) != initializing_class_definitions_.end()) {
+ WaitForClassInitializationToFinish();
+ }
+ it = std::find(initialized_class_definitions_.begin(),
+ initialized_class_definitions_.end(),
+ def);
+ CHECK(it != initialized_class_definitions_.end()) << "Could not find class definition for "
+ << def->GetName();
+ initialized_class_definitions_.erase(it);
+ }
+
+ void AddArtDefinition(ArtClassDefinition* def) REQUIRES(!uninitialized_class_definitions_lock_) {
+ DCHECK(def->IsLazyDefinition());
+ art::MutexLock mu(art::Thread::Current(), uninitialized_class_definitions_lock_);
+ uninitialized_class_definitions_.push_back(def);
+ }
+
+ private:
+ bool DefinitionIsInitializing(uintptr_t ptr) REQUIRES(uninitialized_class_definitions_lock_) {
+ return std::find_if(initializing_class_definitions_.begin(),
+ initializing_class_definitions_.end(),
+ [&](const auto op) { return op->ContainsAddress(ptr); }) !=
+ initializing_class_definitions_.end();
+ }
+
+ void WaitForClassInitializationToFinish() REQUIRES(uninitialized_class_definitions_lock_) {
+ class_definition_initialized_cond_.Wait(art::Thread::Current());
+ }
+
+ art::Mutex uninitialized_class_definitions_lock_ ACQUIRED_BEFORE(art::Locks::abort_lock_);
+ art::ConditionVariable class_definition_initialized_cond_
+ GUARDED_BY(uninitialized_class_definitions_lock_);
+
+ // A list of the class definitions that have a non-readable map.
+ std::vector<ArtClassDefinition*> uninitialized_class_definitions_
+ GUARDED_BY(uninitialized_class_definitions_lock_);
+
+ // A list of class definitions that are currently undergoing unquickening. Threads should wait
+ // until the definition is no longer in this before returning.
+ std::vector<ArtClassDefinition*> initializing_class_definitions_
+ GUARDED_BY(uninitialized_class_definitions_lock_);
+
+ // A list of class definitions that are already unquickened. Threads should immediately return if
+ // it is here.
+ std::vector<ArtClassDefinition*> initialized_class_definitions_
+ GUARDED_BY(uninitialized_class_definitions_lock_);
+};
+
+static TransformationFaultHandler* gTransformFaultHandler = nullptr;
+
+void Transformer::Setup() {
+ // Although we create this the fault handler is actually owned by the 'art::fault_manager' which
+ // will take care of destroying it.
+ if (art::MemMap::kCanReplaceMapping && ArtClassDefinition::kEnableOnDemandDexDequicken) {
+ gTransformFaultHandler = new TransformationFaultHandler(&art::fault_manager);
+ }
+}
+
+// Simple helper to add and remove the class definition from the fault handler.
+class ScopedDefinitionHandler {
+ public:
+ explicit ScopedDefinitionHandler(ArtClassDefinition* def)
+ : def_(def), is_lazy_(def_->IsLazyDefinition()) {
+ if (is_lazy_) {
+ gTransformFaultHandler->AddArtDefinition(def_);
+ }
+ }
+
+ ~ScopedDefinitionHandler() {
+ if (is_lazy_) {
+ gTransformFaultHandler->RemoveDefinition(def_);
+ }
+ }
+
+ private:
+ ArtClassDefinition* def_;
+ bool is_lazy_;
+};
+
+// Initialize templates.
+template
+void Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
+ EventHandler* event_handler, art::Thread* self, /*in-out*/ArtClassDefinition* def);
+template
+void Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
+ EventHandler* event_handler, art::Thread* self, /*in-out*/ArtClassDefinition* def);
+
+template<ArtJvmtiEvent kEvent>
+void Transformer::TransformSingleClassDirect(EventHandler* event_handler,
+ art::Thread* self,
+ /*in-out*/ArtClassDefinition* def) {
+ static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable ||
+ kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable,
+ "bad event type");
+ // We don't want to do transitions between calling the event and setting the new data so change to
+ // native state early. This also avoids any problems that the FaultHandler might have in
+ // determining if an access to the dex_data is from generated code or not.
+ art::ScopedThreadStateChange stsc(self, art::ThreadState::kNative);
+ ScopedDefinitionHandler handler(def);
+ jint new_len = -1;
+ unsigned char* new_data = nullptr;
+ art::ArrayRef<const unsigned char> dex_data = def->GetDexData();
+ event_handler->DispatchEvent<kEvent>(
+ self,
+ static_cast<JNIEnv*>(self->GetJniEnv()),
+ def->GetClass(),
+ def->GetLoader(),
+ def->GetName().c_str(),
+ def->GetProtectionDomain(),
+ static_cast<jint>(dex_data.size()),
+ dex_data.data(),
+ /*out*/&new_len,
+ /*out*/&new_data);
+ def->SetNewDexData(new_len, new_data);
+}
+
jvmtiError Transformer::RetransformClassesDirect(
- ArtJvmTiEnv* env,
EventHandler* event_handler,
art::Thread* self,
/*in-out*/std::vector<ArtClassDefinition>* definitions) {
for (ArtClassDefinition& def : *definitions) {
- jint new_len = -1;
- unsigned char* new_data = nullptr;
- art::ArrayRef<const unsigned char> dex_data = def.GetDexData();
- event_handler->DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
- self,
- GetJniEnv(env),
- def.GetClass(),
- def.GetLoader(),
- def.GetName().c_str(),
- def.GetProtectionDomain(),
- static_cast<jint>(dex_data.size()),
- dex_data.data(),
- /*out*/&new_len,
- /*out*/&new_data);
- def.SetNewDexData(env, new_len, new_data);
+ TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(event_handler,
+ self,
+ &def);
}
return OK;
}
@@ -120,13 +321,13 @@ jvmtiError Transformer::RetransformClasses(ArtJvmTiEnv* env,
return ERR(UNMODIFIABLE_CLASS);
}
ArtClassDefinition def;
- res = def.Init(env, classes[i]);
+ res = def.Init(self, classes[i]);
if (res != OK) {
return res;
}
definitions.push_back(std::move(def));
}
- res = RetransformClassesDirect(env, event_handler, self, &definitions);
+ res = RetransformClassesDirect(event_handler, self, &definitions);
if (res != OK) {
return res;
}