Revert "Initial support for adding virtuals with structural redefinition"
This reverts commit 283bb322de84ac570b987c65a1015e2dbcbfad7c.
Reason for revert: Test flakes
Bug: 134162467
Bug: 144168550
Bug: 144590579
Change-Id: I2259c030f03a72f6b7bcda10288bd23cb3258164
diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp
index 37ae951..e7306ba 100644
--- a/openjdkjvmti/Android.bp
+++ b/openjdkjvmti/Android.bp
@@ -26,7 +26,6 @@
defaults: ["art_defaults"],
host_supported: true,
srcs: [
- "alloc_manager.cc",
"deopt_manager.cc",
"events.cc",
"fixed_up_dex_file.cc",
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index 4ce376f..665fa9f 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -40,7 +40,6 @@
#include "jvmti.h"
-#include "alloc_manager.h"
#include "art_jvmti.h"
#include "base/logging.h" // For gLogVerbosity.
#include "base/mutex.h"
@@ -80,7 +79,6 @@
// These should never be null.
EventHandler* gEventHandler;
DeoptManager* gDeoptManager;
-AllocationManager* gAllocManager;
#define ENSURE_NON_NULL(n) \
do { \
@@ -1499,7 +1497,6 @@
extern "C" bool ArtPlugin_Initialize() {
art::Runtime* runtime = art::Runtime::Current();
- gAllocManager = new AllocationManager;
gDeoptManager = new DeoptManager;
gEventHandler = new EventHandler;
diff --git a/openjdkjvmti/alloc_manager.cc b/openjdkjvmti/alloc_manager.cc
deleted file mode 100644
index 597ab05..0000000
--- a/openjdkjvmti/alloc_manager.cc
+++ /dev/null
@@ -1,187 +0,0 @@
-
-/* Copyright (C) 2019 The Android Open Source Project
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This file implements interfaces from the file jvmti.h. This implementation
- * is licensed under the same terms as the file jvmti.h. The
- * copyright and license information for the file jvmti.h follows.
- *
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "alloc_manager.h"
-
-#include <atomic>
-#include <sstream>
-
-#include "base/logging.h"
-#include "gc/allocation_listener.h"
-#include "gc/heap.h"
-#include "handle.h"
-#include "mirror/class-inl.h"
-#include "runtime.h"
-#include "scoped_thread_state_change-inl.h"
-#include "scoped_thread_state_change.h"
-#include "thread-current-inl.h"
-#include "thread_list.h"
-#include "thread_pool.h"
-
-namespace openjdkjvmti {
-
-template<typename T>
-void AllocationManager::PauseForAllocation(art::Thread* self, T msg) {
- // The suspension can pause us for arbitrary times. We need to do it to sleep unfortunately. So we
- // do test, suspend, test again, sleep, repeat.
- std::string cause;
- const bool is_logging = VLOG_IS_ON(plugin);
- while (true) {
- // We always return when there is no pause and we are runnable.
- art::Thread* pausing_thread = allocations_paused_thread_.load(std::memory_order_seq_cst);
- if (LIKELY(pausing_thread == nullptr || pausing_thread == self)) {
- return;
- }
- if (UNLIKELY(is_logging && cause.empty())) {
- cause = msg();
- }
- art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
- art::MutexLock mu(self, alloc_listener_mutex_);
- pausing_thread = allocations_paused_thread_.load(std::memory_order_seq_cst);
- CHECK_NE(pausing_thread, self) << "We should always be setting pausing_thread = self!"
- << " How did this happen? " << *self;
- if (pausing_thread != nullptr) {
- VLOG(plugin) << "Suspending " << *self << " due to " << cause << ". Allocation pause "
- << "initiated by " << *pausing_thread;
- alloc_pause_cv_.Wait(self);
- }
- }
-}
-
-extern AllocationManager* gAllocManager;
-AllocationManager* AllocationManager::Get() {
- return gAllocManager;
-}
-
-void JvmtiAllocationListener::ObjectAllocated(art::Thread* self,
- art::ObjPtr<art::mirror::Object>* obj,
- size_t cnt) {
- auto cb = manager_->callback_;
- if (cb != nullptr && manager_->callback_enabled_.load(std::memory_order_seq_cst)) {
- cb->ObjectAllocated(self, obj, cnt);
- }
-}
-
-bool JvmtiAllocationListener::HasPreAlloc() const {
- return manager_->allocations_paused_thread_.load(std::memory_order_seq_cst) != nullptr;
-}
-
-void JvmtiAllocationListener::PreObjectAllocated(art::Thread* self,
- art::MutableHandle<art::mirror::Class> type,
- size_t* byte_count) {
- manager_->PauseForAllocation(self, [&]() REQUIRES_SHARED(art::Locks::mutator_lock_) {
- std::ostringstream oss;
- oss << "allocating " << *byte_count << " bytes of type " << type->PrettyClass();
- return oss.str();
- });
- if (!type->IsVariableSize()) {
- *byte_count = type->GetObjectSize();
- }
-}
-
-AllocationManager::AllocationManager()
- : alloc_listener_(nullptr),
- alloc_listener_mutex_("JVMTI Alloc listener",
- art::LockLevel::kPostUserCodeSuspensionTopLevelLock),
- alloc_pause_cv_("JVMTI Allocation Pause Condvar", alloc_listener_mutex_) {
- alloc_listener_.reset(new JvmtiAllocationListener(this));
-}
-
-void AllocationManager::DisableAllocationCallback(art::Thread* self) {
- callback_enabled_.store(false);
- DecrListenerInstall(self);
-}
-
-void AllocationManager::EnableAllocationCallback(art::Thread* self) {
- IncrListenerInstall(self);
- callback_enabled_.store(true);
-}
-
-void AllocationManager::SetAllocListener(AllocationCallback* callback) {
- CHECK(callback_ == nullptr) << "Already setup!";
- callback_ = callback;
- alloc_listener_.reset(new JvmtiAllocationListener(this));
-}
-
-void AllocationManager::RemoveAllocListener() {
- callback_enabled_.store(false, std::memory_order_seq_cst);
- callback_ = nullptr;
-}
-
-void AllocationManager::DecrListenerInstall(art::Thread* self) {
- art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
- art::MutexLock mu(self, alloc_listener_mutex_);
- // We don't need any particular memory-order here since we're under the lock, they aren't
- // changing.
- if (--listener_refcount_ == 0) {
- art::Runtime::Current()->GetHeap()->RemoveAllocationListener();
- }
-}
-
-void AllocationManager::IncrListenerInstall(art::Thread* self) {
- art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
- art::MutexLock mu(self, alloc_listener_mutex_);
- // We don't need any particular memory-order here since we're under the lock, they aren't
- // changing.
- if (listener_refcount_++ == 0) {
- art::Runtime::Current()->GetHeap()->SetAllocationListener(alloc_listener_.get());
- }
-}
-
-void AllocationManager::PauseAllocations(art::Thread* self) {
- art::Thread* null_thr = nullptr;
- IncrListenerInstall(self);
- do {
- PauseForAllocation(self, []() { return "request to pause allocations on other threads"; });
- } while (allocations_paused_thread_.compare_exchange_strong(
- null_thr, self, std::memory_order_seq_cst));
- // Make sure everything else can see this and isn't in the middle of final allocation.
- // Force every thread to either be suspended or pass through a barrier.
- art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
- art::Barrier barrier(0);
- art::FunctionClosure fc([&](art::Thread* thr ATTRIBUTE_UNUSED) {
- barrier.Pass(art::Thread::Current());
- });
- size_t requested = art::Runtime::Current()->GetThreadList()->RunCheckpoint(&fc);
- barrier.Increment(self, requested);
-}
-
-void AllocationManager::ResumeAllocations(art::Thread* self) {
- CHECK_EQ(allocations_paused_thread_.load(), self) << "not paused! ";
- DecrListenerInstall(self);
- art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
- art::MutexLock mu(self, alloc_listener_mutex_);
- allocations_paused_thread_.store(nullptr, std::memory_order_seq_cst);
- alloc_pause_cv_.Broadcast(self);
-}
-
-} // namespace openjdkjvmti
diff --git a/openjdkjvmti/alloc_manager.h b/openjdkjvmti/alloc_manager.h
deleted file mode 100644
index c89d9a6..0000000
--- a/openjdkjvmti/alloc_manager.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/* Copyright (C) 2019 The Android Open Source Project
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This file implements interfaces from the file jvmti.h. This implementation
- * is licensed under the same terms as the file jvmti.h. The
- * copyright and license information for the file jvmti.h follows.
- *
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#ifndef ART_OPENJDKJVMTI_ALLOC_MANAGER_H_
-#define ART_OPENJDKJVMTI_ALLOC_MANAGER_H_
-
-#include <jvmti.h>
-
-#include <atomic>
-
-#include "base/locks.h"
-#include "base/mutex.h"
-#include "gc/allocation_listener.h"
-
-namespace art {
-template <typename T> class MutableHandle;
-template <typename T> class ObjPtr;
-class Thread;
-namespace mirror {
-class Class;
-class Object;
-} // namespace mirror
-} // namespace art
-
-namespace openjdkjvmti {
-
-class AllocationManager;
-
-class JvmtiAllocationListener : public art::gc::AllocationListener {
- public:
- explicit JvmtiAllocationListener(AllocationManager* manager) : manager_(manager) {}
- void ObjectAllocated(art::Thread* self,
- art::ObjPtr<art::mirror::Object>* obj,
- size_t cnt) override REQUIRES_SHARED(art::Locks::mutator_lock_);
- bool HasPreAlloc() const override REQUIRES_SHARED(art::Locks::mutator_lock_);
- void PreObjectAllocated(art::Thread* self,
- art::MutableHandle<art::mirror::Class> type,
- size_t* byte_count) override REQUIRES_SHARED(art::Locks::mutator_lock_);
-
- private:
- AllocationManager* manager_;
-};
-
-class AllocationManager {
- public:
- class AllocationCallback {
- public:
- virtual ~AllocationCallback() {}
- virtual void ObjectAllocated(art::Thread* self,
- art::ObjPtr<art::mirror::Object>* obj,
- size_t byte_count) REQUIRES_SHARED(art::Locks::mutator_lock_) = 0;
- };
-
- AllocationManager();
-
- void SetAllocListener(AllocationCallback* callback);
- void RemoveAllocListener();
-
- static AllocationManager* Get();
-
- void PauseAllocations(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_);
- void ResumeAllocations(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_);
-
- void EnableAllocationCallback(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_);
- void DisableAllocationCallback(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_);
-
- private:
- template<typename T>
- void PauseForAllocation(art::Thread* self, T msg) REQUIRES_SHARED(art::Locks::mutator_lock_);
- void IncrListenerInstall(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_);
- void DecrListenerInstall(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_);
-
- AllocationCallback* callback_ = nullptr;
- uint32_t listener_refcount_ GUARDED_BY(alloc_listener_mutex_) = 0;
- std::atomic<art::Thread*> allocations_paused_thread_ = nullptr;
- std::atomic<bool> callback_enabled_ = false;
- std::unique_ptr<JvmtiAllocationListener> alloc_listener_ = nullptr;
- art::Mutex alloc_listener_mutex_ ACQUIRED_AFTER(art::Locks::user_code_suspension_lock_);
- art::ConditionVariable alloc_pause_cv_;
-
- friend class JvmtiAllocationListener;
-};
-
-} // namespace openjdkjvmti
-
-#endif // ART_OPENJDKJVMTI_ALLOC_MANAGER_H_
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index 64a02e8..56406fc 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -31,7 +31,6 @@
#include <android-base/thread_annotations.h>
-#include "alloc_manager.h"
#include "base/locks.h"
#include "base/mutex.h"
#include "events-inl.h"
@@ -313,9 +312,9 @@
DISALLOW_COPY_AND_ASSIGN(JvmtiDdmChunkListener);
};
-class JvmtiEventAllocationListener : public AllocationManager::AllocationCallback {
+class JvmtiAllocationListener : public art::gc::AllocationListener {
public:
- explicit JvmtiEventAllocationListener(EventHandler* handler) : handler_(handler) {}
+ explicit JvmtiAllocationListener(EventHandler* handler) : handler_(handler) {}
void ObjectAllocated(art::Thread* self, art::ObjPtr<art::mirror::Object>* obj, size_t byte_count)
override REQUIRES_SHARED(art::Locks::mutator_lock_) {
@@ -350,14 +349,15 @@
EventHandler* handler_;
};
-static void SetupObjectAllocationTracking(bool enable) {
+static void SetupObjectAllocationTracking(art::gc::AllocationListener* listener, bool enable) {
// We must not hold the mutator lock here, but if we're in FastJNI, for example, we might. For
// now, do a workaround: (possibly) acquire and release.
art::ScopedObjectAccess soa(art::Thread::Current());
+ art::ScopedThreadSuspension sts(soa.Self(), art::ThreadState::kSuspended);
if (enable) {
- AllocationManager::Get()->EnableAllocationCallback(soa.Self());
+ art::Runtime::Current()->GetHeap()->SetAllocationListener(listener);
} else {
- AllocationManager::Get()->DisableAllocationCallback(soa.Self());
+ art::Runtime::Current()->GetHeap()->RemoveAllocationListener();
}
}
@@ -1327,7 +1327,7 @@
SetupDdmTracking(ddm_listener_.get(), enable);
return;
case ArtJvmtiEvent::kVmObjectAlloc:
- SetupObjectAllocationTracking(enable);
+ SetupObjectAllocationTracking(alloc_listener_.get(), enable);
return;
case ArtJvmtiEvent::kGarbageCollectionStart:
case ArtJvmtiEvent::kGarbageCollectionFinish:
@@ -1665,15 +1665,13 @@
art::ScopedSuspendAll ssa("jvmti method tracing uninstallation");
// Just remove every possible event.
art::Runtime::Current()->GetInstrumentation()->RemoveListener(method_trace_listener_.get(), ~0);
- AllocationManager::Get()->RemoveAllocListener();
}
EventHandler::EventHandler()
: envs_lock_("JVMTI Environment List Lock", art::LockLevel::kPostMutatorTopLockLevel),
frame_pop_enabled(false),
internal_event_refcount_({0}) {
- alloc_listener_.reset(new JvmtiEventAllocationListener(this));
- AllocationManager::Get()->SetAllocListener(alloc_listener_.get());
+ alloc_listener_.reset(new JvmtiAllocationListener(this));
ddm_listener_.reset(new JvmtiDdmChunkListener(this));
gc_pause_listener_.reset(new JvmtiGcPauseListener(this));
method_trace_listener_.reset(new JvmtiMethodTraceListener(this));
diff --git a/openjdkjvmti/events.h b/openjdkjvmti/events.h
index d4eb171..c9d587a 100644
--- a/openjdkjvmti/events.h
+++ b/openjdkjvmti/events.h
@@ -34,7 +34,7 @@
namespace openjdkjvmti {
struct ArtJvmTiEnv;
-class JvmtiEventAllocationListener;
+class JvmtiAllocationListener;
class JvmtiDdmChunkListener;
class JvmtiGcPauseListener;
class JvmtiMethodTraceListener;
@@ -425,7 +425,7 @@
// A union of all enabled events, anywhere.
EventMask global_mask;
- std::unique_ptr<JvmtiEventAllocationListener> alloc_listener_;
+ std::unique_ptr<JvmtiAllocationListener> alloc_listener_;
std::unique_ptr<JvmtiDdmChunkListener> ddm_listener_;
std::unique_ptr<JvmtiGcPauseListener> gc_pause_listener_;
std::unique_ptr<JvmtiMethodTraceListener> method_trace_listener_;
diff --git a/openjdkjvmti/ti_heap.cc b/openjdkjvmti/ti_heap.cc
index b25b4d1..1d18390 100644
--- a/openjdkjvmti/ti_heap.cc
+++ b/openjdkjvmti/ti_heap.cc
@@ -17,7 +17,6 @@
#include "ti_heap.h"
#include <ios>
-#include <unordered_map>
#include "android-base/logging.h"
#include "android-base/thread_annotations.h"
@@ -1614,9 +1613,8 @@
namespace {
using ObjectPtr = art::ObjPtr<art::mirror::Object>;
-using ObjectMap = std::unordered_map<ObjectPtr, ObjectPtr, art::HashObjPtr>;
-static void ReplaceObjectReferences(const ObjectMap& map)
+static void ReplaceObjectReferences(ObjectPtr old_obj_ptr, ObjectPtr new_obj_ptr)
REQUIRES(art::Locks::mutator_lock_,
art::Roles::uninterruptible_) {
art::Runtime::Current()->GetHeap()->VisitObjectsPaused(
@@ -1625,7 +1623,8 @@
class ResizeReferenceVisitor {
public:
using CompressedObj = art::mirror::CompressedReference<art::mirror::Object>;
- explicit ResizeReferenceVisitor(const ObjectMap& map) : map_(map) {}
+ ResizeReferenceVisitor(ObjectPtr old_arr, ObjectPtr new_arr)
+ : old_obj_(old_arr), new_obj_(new_arr) {}
// Ignore class roots.
void VisitRootIfNonNull(CompressedObj* root) const
@@ -1635,29 +1634,20 @@
}
}
void VisitRoot(CompressedObj* root) const REQUIRES_SHARED(art::Locks::mutator_lock_) {
- auto it = map_.find(root->AsMirrorPtr());
- if (it != map_.end()) {
- root->Assign(it->second);
- art::WriteBarrier::ForEveryFieldWrite(it->second);
+ if (root->AsMirrorPtr() == old_obj_) {
+ root->Assign(new_obj_);
+ art::WriteBarrier::ForEveryFieldWrite(new_obj_);
}
}
void operator()(art::ObjPtr<art::mirror::Object> obj,
art::MemberOffset off,
- bool is_static) const
+ bool is_static ATTRIBUTE_UNUSED) const
REQUIRES_SHARED(art::Locks::mutator_lock_) {
- auto it = map_.find(obj->GetFieldObject<art::mirror::Object>(off));
- if (it != map_.end()) {
- UNUSED(is_static);
- if (UNLIKELY(!is_static && off == art::mirror::Object::ClassOffset())) {
- // We don't want to update the declaring class of any objects. They will be replaced
- // in the heap and we need the declaring class to know its size.
- return;
- }
+ if (obj->GetFieldObject<art::mirror::Object>(off) == old_obj_) {
VLOG(plugin) << "Updating field at offset " << off.Uint32Value() << " of type "
<< obj->GetClass()->PrettyClass();
- obj->SetFieldObject</*transaction*/ false>(off, it->second);
- art::WriteBarrier::ForEveryFieldWrite(obj);
+ obj->SetFieldObject</*transaction*/ false>(off, new_obj_);
}
}
@@ -1669,10 +1659,11 @@
}
private:
- const ObjectMap& map_;
+ ObjectPtr old_obj_;
+ ObjectPtr new_obj_;
};
- ResizeReferenceVisitor rrv(map);
+ ResizeReferenceVisitor rrv(old_obj_ptr, new_obj_ptr);
if (ref->IsClass()) {
// Class object native roots are the ArtField and ArtMethod 'declaring_class_' fields
// which we don't want to be messing with as it would break ref-visitor assumptions about
@@ -1687,12 +1678,13 @@
});
}
-static void ReplaceStrongRoots(art::Thread* self, const ObjectMap& map)
+static void ReplaceStrongRoots(art::Thread* self, ObjectPtr old_obj_ptr, ObjectPtr new_obj_ptr)
REQUIRES(art::Locks::mutator_lock_, art::Roles::uninterruptible_) {
// replace root references expcept java frames.
struct ResizeRootVisitor : public art::RootVisitor {
public:
- explicit ResizeRootVisitor(const ObjectMap& map) : map_(map) {}
+ ResizeRootVisitor(ObjectPtr new_val, ObjectPtr old_val)
+ : new_val_(new_val), old_val_(old_val) {}
// TODO It's somewhat annoying to have to have this function implemented twice. It might be
// good/useful to implement operator= for CompressedReference to allow us to use a template to
@@ -1701,8 +1693,7 @@
REQUIRES_SHARED(art::Locks::mutator_lock_) {
art::mirror::Object*** end = roots + count;
for (art::mirror::Object** obj = *roots; roots != end; obj = *(++roots)) {
- auto it = map_.find(*obj);
- if (it != map_.end()) {
+ if (*obj == old_val_) {
// Java frames might have the JIT doing optimizations (for example loop-unrolling or
// eliding bounds checks) so we need deopt them once we're done here.
if (info.GetType() == art::RootType::kRootJavaFrame) {
@@ -1717,7 +1708,7 @@
threads_with_roots_.insert(info.GetThreadId());
}
}
- *obj = it->second.Ptr();
+ *obj = new_val_.Ptr();
}
}
}
@@ -1728,8 +1719,7 @@
art::mirror::CompressedReference<art::mirror::Object>** end = roots + count;
for (art::mirror::CompressedReference<art::mirror::Object>* obj = *roots; roots != end;
obj = *(++roots)) {
- auto it = map_.find(obj->AsMirrorPtr());
- if (it != map_.end()) {
+ if (obj->AsMirrorPtr() == old_val_) {
// Java frames might have the JIT doing optimizations (for example loop-unrolling or
// eliding bounds checks) so we need deopt them once we're done here.
if (info.GetType() == art::RootType::kRootJavaFrame) {
@@ -1744,7 +1734,7 @@
threads_with_roots_.insert(info.GetThreadId());
}
}
- obj->Assign(it->second);
+ obj->Assign(new_val_);
}
}
}
@@ -1754,10 +1744,11 @@
}
private:
- const ObjectMap& map_;
+ ObjectPtr new_val_;
+ ObjectPtr old_val_;
std::unordered_set<uint32_t> threads_with_roots_;
};
- ResizeRootVisitor rrv(map);
+ ResizeRootVisitor rrv(new_obj_ptr, old_obj_ptr);
art::Runtime::Current()->VisitRoots(&rrv, art::VisitRootFlags::kVisitRootFlagAllRoots);
// Handle java Frames. Annoyingly the JIT can embed information about the length of the array into
// the compiled code. By changing the length of the array we potentially invalidate these
@@ -1782,7 +1773,8 @@
static void ReplaceWeakRoots(art::Thread* self,
EventHandler* event_handler,
- const ObjectMap& map)
+ ObjectPtr old_obj_ptr,
+ ObjectPtr new_obj_ptr)
REQUIRES(art::Locks::mutator_lock_, art::Roles::uninterruptible_) {
// Handle tags. We want to do this seprately from other weak-refs (handled below) because we need
// to send additional events and handle cases where the agent might have tagged the new
@@ -1794,33 +1786,25 @@
// situations where the order of weak-ref visiting affects the final tagging state. Since we have
// the mutator_lock_ and gc-paused throughout this whole process no threads should be able to see
// the interval where the objects are not tagged.
- struct NewTagValue {
- public:
- ObjectPtr obsolete_obj_;
- jlong obsolete_tag_;
- ObjectPtr new_obj_;
- jlong new_tag_;
- };
-
- // Map from the environment to the list of <obsolete_tag, new_tag> pairs that were changed.
- std::unordered_map<ArtJvmTiEnv*, std::vector<NewTagValue>> changed_tags;
+ std::unordered_map<ArtJvmTiEnv*, jlong> obsolete_tags;
+ std::unordered_map<ArtJvmTiEnv*, jlong> non_obsolete_tags;
event_handler->ForEachEnv(self, [&](ArtJvmTiEnv* env) {
// Cannot have REQUIRES(art::Locks::mutator_lock_) since ForEachEnv doesn't require it.
art::Locks::mutator_lock_->AssertExclusiveHeld(self);
env->object_tag_table->Lock();
// Get the tags and clear them (so we don't need to special-case the normal weak-ref visitor)
- for (auto it : map) {
- jlong new_tag = 0;
- jlong obsolete_tag = 0;
- bool had_obsolete_tag = env->object_tag_table->RemoveLocked(it.first, &obsolete_tag);
- bool had_new_tag = env->object_tag_table->RemoveLocked(it.second, &new_tag);
- // Dispatch event.
- if (had_obsolete_tag || had_new_tag) {
- event_handler->DispatchEventOnEnv<ArtJvmtiEvent::kObsoleteObjectCreated>(
- env, self, &obsolete_tag, &new_tag);
- changed_tags.try_emplace(env).first->second.push_back(
- { it.first, obsolete_tag, it.second, new_tag });
- }
+ jlong new_tag = 0;
+ jlong obsolete_tag = 0;
+ bool had_new_tag = env->object_tag_table->RemoveLocked(new_obj_ptr, &new_tag);
+ bool had_obsolete_tag = env->object_tag_table->RemoveLocked(old_obj_ptr, &obsolete_tag);
+ // Dispatch event.
+ if (had_obsolete_tag || had_new_tag) {
+ event_handler->DispatchEventOnEnv<ArtJvmtiEvent::kObsoleteObjectCreated>(env,
+ self,
+ &obsolete_tag,
+ &new_tag);
+ obsolete_tags[env] = obsolete_tag;
+ non_obsolete_tags[env] = new_tag;
}
// After weak-ref update we need to go back and re-add obsoletes. We wait to avoid having to
// deal with the visit-weaks overwriting the initial new_obj_ptr tag and generally making things
@@ -1830,34 +1814,34 @@
// Handle weak-refs.
struct ReplaceWeaksVisitor : public art::IsMarkedVisitor {
public:
- ReplaceWeaksVisitor(const ObjectMap& map) : map_(map) {}
+ ReplaceWeaksVisitor(ObjectPtr old_obj, ObjectPtr new_obj)
+ : old_obj_(old_obj), new_obj_(new_obj) {}
art::mirror::Object* IsMarked(art::mirror::Object* obj)
REQUIRES_SHARED(art::Locks::mutator_lock_) {
- auto it = map_.find(obj);
- if (it != map_.end()) {
- return it->second.Ptr();
+ if (obj == old_obj_) {
+ return new_obj_.Ptr();
} else {
return obj;
}
}
private:
- const ObjectMap& map_;
+ ObjectPtr old_obj_;
+ ObjectPtr new_obj_;
};
- ReplaceWeaksVisitor rwv(map);
+ ReplaceWeaksVisitor rwv(old_obj_ptr, new_obj_ptr);
art::Runtime::Current()->SweepSystemWeaks(&rwv);
// Re-add the object tags. At this point all weak-references to the old_obj_ptr are gone.
event_handler->ForEachEnv(self, [&](ArtJvmTiEnv* env) {
// Cannot have REQUIRES(art::Locks::mutator_lock_) since ForEachEnv doesn't require it.
art::Locks::mutator_lock_->AssertExclusiveHeld(self);
env->object_tag_table->Lock();
- auto it = changed_tags.find(env);
- if (it != changed_tags.end()) {
- for (const NewTagValue& v : it->second) {
- env->object_tag_table->SetLocked(v.obsolete_obj_, v.obsolete_tag_);
- env->object_tag_table->SetLocked(v.new_obj_, v.new_tag_);
- }
+ if (obsolete_tags.find(env) != obsolete_tags.end()) {
+ env->object_tag_table->SetLocked(old_obj_ptr, obsolete_tags[env]);
+ }
+ if (non_obsolete_tags.find(env) != non_obsolete_tags.end()) {
+ env->object_tag_table->SetLocked(new_obj_ptr, non_obsolete_tags[env]);
}
env->object_tag_table->Unlock();
});
@@ -1868,14 +1852,9 @@
void HeapExtensions::ReplaceReference(art::Thread* self,
art::ObjPtr<art::mirror::Object> old_obj_ptr,
art::ObjPtr<art::mirror::Object> new_obj_ptr) {
- ObjectMap map { { old_obj_ptr, new_obj_ptr } };
- ReplaceReferences(self, map);
-}
-
-void HeapExtensions::ReplaceReferences(art::Thread* self, const ObjectMap& map) {
- ReplaceObjectReferences(map);
- ReplaceStrongRoots(self, map);
- ReplaceWeakRoots(self, HeapExtensions::gEventHandler, map);
+ ReplaceObjectReferences(old_obj_ptr, new_obj_ptr);
+ ReplaceStrongRoots(self, old_obj_ptr, new_obj_ptr);
+ ReplaceWeakRoots(self, HeapExtensions::gEventHandler, old_obj_ptr, new_obj_ptr);
}
jvmtiError HeapExtensions::ChangeArraySize(jvmtiEnv* env, jobject arr, jsize new_size) {
diff --git a/openjdkjvmti/ti_heap.h b/openjdkjvmti/ti_heap.h
index ee8b4d6..2e27cc7 100644
--- a/openjdkjvmti/ti_heap.h
+++ b/openjdkjvmti/ti_heap.h
@@ -17,8 +17,6 @@
#ifndef ART_OPENJDKJVMTI_TI_HEAP_H_
#define ART_OPENJDKJVMTI_TI_HEAP_H_
-#include <unordered_map>
-
#include "jvmti.h"
#include "base/locks.h"
@@ -26,7 +24,6 @@
namespace art {
class Thread;
template<typename T> class ObjPtr;
-class HashObjPtr;
namespace mirror {
class Object;
} // namespace mirror
@@ -91,13 +88,6 @@
static jvmtiError JNICALL ChangeArraySize(jvmtiEnv* env, jobject arr, jsize new_size);
- static void ReplaceReferences(
- art::Thread* self,
- const std::unordered_map<art::ObjPtr<art::mirror::Object>,
- art::ObjPtr<art::mirror::Object>,
- art::HashObjPtr>& refs)
- REQUIRES(art::Locks::mutator_lock_, art::Roles::uninterruptible_);
-
static void ReplaceReference(art::Thread* self,
art::ObjPtr<art::mirror::Object> original,
art::ObjPtr<art::mirror::Object> replacement)
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index ebbe6ac..87080ca 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -42,8 +42,6 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
-#include "alloc_manager.h"
-#include "android-base/macros.h"
#include "android-base/thread_annotations.h"
#include "art_field-inl.h"
#include "art_field.h"
@@ -117,7 +115,6 @@
#include "reflective_value_visitor.h"
#include "runtime.h"
#include "runtime_globals.h"
-#include "scoped_thread_state_change.h"
#include "stack.h"
#include "thread.h"
#include "thread_list.h"
@@ -463,33 +460,30 @@
}
// Check for already existing non-static fields/methods.
// TODO Remove this once we support generic method/field addition.
- if (!klass->IsFinal()) {
- bool non_static_method = false;
- klass->VisitMethods([&](art::ArtMethod* m) REQUIRES_SHARED(art::Locks::mutator_lock_) {
- // Since direct-methods (ie privates + <init> are not in any vtable/iftable we can update
- // them).
- if (!m->IsDirect()) {
- non_static_method = true;
- *error_msg = StringPrintf("%s has a non-direct function %s",
- klass->PrettyClass().c_str(),
- m->PrettyMethod().c_str());
- }
- }, art::kRuntimePointerSize);
- if (non_static_method) {
- return ERR(UNMODIFIABLE_CLASS);
+ bool non_static_method = false;
+ klass->VisitMethods([&](art::ArtMethod* m) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ // Since direct-methods (ie privates + <init> are not in any vtable/iftable we can update
+ // them).
+ if (!m->IsDirect()) {
+ non_static_method = true;
+ *error_msg = StringPrintf("%s has a non-direct function %s",
+ klass->PrettyClass().c_str(),
+ m->PrettyMethod().c_str());
}
- bool non_static_field = false;
- klass->VisitFields([&](art::ArtField* f) REQUIRES_SHARED(art::Locks::mutator_lock_) {
- if (!f->IsStatic()) {
- non_static_field = true;
- *error_msg = StringPrintf("%s has a non-static field %s",
- klass->PrettyClass().c_str(),
- f->PrettyField().c_str());
- }
- });
- if (non_static_field) {
- return ERR(UNMODIFIABLE_CLASS);
+ }, art::kRuntimePointerSize);
+ if (non_static_method) {
+ return ERR(UNMODIFIABLE_CLASS);
+ }
+ bool non_static_field = false;
+ klass->VisitFields([&](art::ArtField* f) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (!f->IsStatic()) {
+ non_static_field = true;
+ *error_msg = StringPrintf(
+ "%s has a non-static field %s", klass->PrettyClass().c_str(), f->PrettyField().c_str());
}
+ });
+ if (non_static_field) {
+ return ERR(UNMODIFIABLE_CLASS);
}
// Check for fields/methods which were returned before moving to index jni id type.
// TODO We might want to rework how this is done. Once full redefinition is implemented we will
@@ -991,12 +985,9 @@
return old_method_id == new_method_id;
});
- if (!new_method.IsStaticOrDirect()) {
- RecordHasVirtualMembers();
- }
if (old_iter == old_methods.cend()) {
// TODO Support adding non-static methods.
- if (is_structural && (new_method.IsStaticOrDirect() || h_klass->IsFinal())) {
+ if (is_structural && new_method.IsStaticOrDirect()) {
RecordNewMethodAdded();
} else {
RecordFailure(
@@ -1055,12 +1046,9 @@
FieldNameAndSignature old_field_id(&old_dex_file, old_iter.GetIndex());
return old_field_id == new_field_id;
});
- if (!new_field.IsStatic()) {
- RecordHasVirtualMembers();
- }
if (old_iter == old_fields.cend()) {
// TODO Support adding non-static fields.
- if (driver_->IsStructuralRedefinition() && (new_field.IsStatic() || h_klass->IsFinal())) {
+ if (driver_->IsStructuralRedefinition() && new_field.IsStatic()) {
RecordNewFieldAdded();
} else {
RecordFailure(ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED),
@@ -1181,10 +1169,6 @@
jvmtiError res;
if (driver_->type_ == RedefinitionType::kStructural && this->IsStructuralRedefinition()) {
res = Redefiner::GetClassRedefinitionError<RedefinitionType::kStructural>(h_klass, &err);
- if (res == OK && HasVirtualMembers() && h_klass->IsFinalizable()) {
- res = ERR(INTERNAL);
- err = "Cannot redefine finalizable objects at this time.";
- }
} else {
res = Redefiner::GetClassRedefinitionError<RedefinitionType::kNormal>(h_klass, &err);
}
@@ -1217,11 +1201,9 @@
kSlotOldObsoleteMethods = 6,
kSlotOldDexCaches = 7,
kSlotNewClassObject = 8,
- kSlotOldInstanceObjects = 9,
- kSlotNewInstanceObjects = 10,
// Must be last one.
- kNumSlots = 11,
+ kNumSlots = 9,
};
// This needs to have a HandleScope passed in that is capable of creating a new Handle without
@@ -1287,18 +1269,6 @@
return art::ObjPtr<art::mirror::Class>::DownCast(GetSlot(klass_index, kSlotNewClassObject));
}
- art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> GetOldInstanceObjects(
- jint klass_index) const REQUIRES_SHARED(art::Locks::mutator_lock_) {
- return art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>>::DownCast(
- GetSlot(klass_index, kSlotOldInstanceObjects));
- }
-
- art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> GetNewInstanceObjects(
- jint klass_index) const REQUIRES_SHARED(art::Locks::mutator_lock_) {
- return art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>>::DownCast(
- GetSlot(klass_index, kSlotNewInstanceObjects));
- }
-
void SetSourceClassLoader(jint klass_index, art::ObjPtr<art::mirror::ClassLoader> loader)
REQUIRES_SHARED(art::Locks::mutator_lock_) {
SetSlot(klass_index, kSlotSourceClassLoader, loader);
@@ -1338,16 +1308,6 @@
SetSlot(klass_index, kSlotNewClassObject, klass);
}
- void SetOldInstanceObjects(jint klass_index,
- art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> objs)
- REQUIRES_SHARED(art::Locks::mutator_lock_) {
- SetSlot(klass_index, kSlotOldInstanceObjects, objs);
- }
- void SetNewInstanceObjects(jint klass_index,
- art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> objs)
- REQUIRES_SHARED(art::Locks::mutator_lock_) {
- SetSlot(klass_index, kSlotNewInstanceObjects, objs);
- }
int32_t Length() const REQUIRES_SHARED(art::Locks::mutator_lock_) {
return arr_->GetLength() / kNumSlots;
}
@@ -1432,11 +1392,6 @@
return *this;
}
- // Compat for STL iterators.
- RedefinitionDataIter& operator*() {
- return *this;
- }
-
Redefiner::ClassRedefinition& GetRedefinition() REQUIRES_SHARED(art::Locks::mutator_lock_) {
return (*holder_.GetRedefinitions())[idx_];
}
@@ -1483,14 +1438,6 @@
return holder_.GetNewClassObject(idx_);
}
- art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> GetOldInstanceObjects() const
- REQUIRES_SHARED(art::Locks::mutator_lock_) {
- return holder_.GetOldInstanceObjects(idx_);
- }
- art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> GetNewInstanceObjects() const
- REQUIRES_SHARED(art::Locks::mutator_lock_) {
- return holder_.GetNewInstanceObjects(idx_);
- }
int32_t GetIndex() const {
return idx_;
}
@@ -1531,14 +1478,6 @@
REQUIRES_SHARED(art::Locks::mutator_lock_) {
holder_.SetNewClassObject(idx_, klass);
}
- void SetOldInstanceObjects(art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> objs)
- REQUIRES_SHARED(art::Locks::mutator_lock_) {
- holder_.SetOldInstanceObjects(idx_, objs);
- }
- void SetNewInstanceObjects(art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> objs)
- REQUIRES_SHARED(art::Locks::mutator_lock_) {
- holder_.SetNewInstanceObjects(idx_, objs);
- }
private:
int32_t idx_;
@@ -1641,75 +1580,6 @@
return true;
}
-bool Redefiner::ClassRedefinition::CollectAndCreateNewInstances(
- /*out*/ RedefinitionDataIter* cur_data) {
- if (!IsStructuralRedefinition()) {
- return true;
- }
- art::VariableSizedHandleScope hs(driver_->self_);
- art::Handle<art::mirror::Class> old_klass(hs.NewHandle(cur_data->GetMirrorClass()));
- std::vector<art::Handle<art::mirror::Object>> old_instances;
- art::gc::Heap* heap = driver_->runtime_->GetHeap();
- auto is_instance = [&](art::mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
- if (HasVirtualMembers()) {
- return old_klass->IsAssignableFrom(obj->GetClass());
- } else {
- // We don't need to deal with objects of subtypes when we don't modify virtuals since the
- // vtable + field layout will remain the same.
- return old_klass.Get() == obj->GetClass();
- }
- };
- heap->VisitObjects([&](art::mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
- if (is_instance(obj)) {
- CHECK(old_klass.Get() == obj->GetClass()) << "No support for subtypes yet!";
- old_instances.push_back(hs.NewHandle(obj));
- }
- });
- VLOG(plugin) << "Collected " << old_instances.size() << " instances to recreate!";
-
- art::Handle<art::mirror::Class> obj_array_class(
- hs.NewHandle(art::GetClassRoot<art::mirror::ObjectArray<art::mirror::Object>>(
- driver_->runtime_->GetClassLinker())));
- art::Handle<art::mirror::ObjectArray<art::mirror::Object>> old_instances_arr(
- hs.NewHandle(art::mirror::ObjectArray<art::mirror::Object>::Alloc(
- driver_->self_, obj_array_class.Get(), old_instances.size())));
- if (old_instances_arr.IsNull()) {
- driver_->self_->AssertPendingOOMException();
- driver_->self_->ClearException();
- RecordFailure(ERR(OUT_OF_MEMORY), "Could not allocate old_instance arrays!");
- return false;
- }
- for (uint32_t i = 0; i < old_instances.size(); ++i) {
- old_instances_arr->Set(i, old_instances[i].Get());
- }
- cur_data->SetOldInstanceObjects(old_instances_arr.Get());
-
- art::Handle<art::mirror::ObjectArray<art::mirror::Object>> new_instances_arr(
- hs.NewHandle(art::mirror::ObjectArray<art::mirror::Object>::Alloc(
- driver_->self_, obj_array_class.Get(), old_instances.size())));
- if (new_instances_arr.IsNull()) {
- driver_->self_->AssertPendingOOMException();
- driver_->self_->ClearException();
- RecordFailure(ERR(OUT_OF_MEMORY), "Could not allocate new_instance arrays!");
- return false;
- }
- art::Handle<art::mirror::Class> new_klass(hs.NewHandle(cur_data->GetNewClassObject()));
- for (uint32_t i = 0; i < old_instances.size(); ++i) {
- art::ObjPtr<art::mirror::Object> new_instance(new_klass->AllocObject(driver_->self_));
- if (new_instance.IsNull()) {
- driver_->self_->AssertPendingOOMException();
- driver_->self_->ClearException();
- std::string msg(
- StringPrintf("Could not allocate instance %d of %zu", i, old_instances.size()));
- RecordFailure(ERR(OUT_OF_MEMORY), msg);
- return false;
- }
- new_instances_arr->Set(i, new_instance);
- }
- cur_data->SetNewInstanceObjects(new_instances_arr.Get());
- return true;
-}
-
bool Redefiner::ClassRedefinition::FinishRemainingAllocations(
/*out*/RedefinitionDataIter* cur_data) {
art::ScopedObjectAccessUnchecked soa(driver_->self_);
@@ -1931,16 +1801,6 @@
return true;
}
-bool Redefiner::CollectAndCreateNewInstances(RedefinitionDataHolder& holder) {
- for (RedefinitionDataIter data = holder.begin(); data != holder.end(); ++data) {
- // Allocate the data this redefinition requires.
- if (!data.GetRedefinition().CollectAndCreateNewInstances(&data)) {
- return false;
- }
- }
- return true;
-}
-
bool Redefiner::FinishAllRemainingAllocations(RedefinitionDataHolder& holder) {
for (RedefinitionDataIter data = holder.begin(); data != holder.end(); ++data) {
// Allocate the data this redefinition requires.
@@ -1989,36 +1849,6 @@
art::Thread* self_;
};
-class ScopedSuspendAllocations {
- public:
- ScopedSuspendAllocations(art::Runtime* runtime, RedefinitionDataHolder& h)
- REQUIRES_SHARED(art::Locks::mutator_lock_)
- : paused_(false) {
- if (std::any_of(h.begin(),
- h.end(),
- [](auto r) REQUIRES_SHARED(art::Locks::mutator_lock_) {
- return r.GetRedefinition().IsStructuralRedefinition();
- })) {
- VLOG(plugin) << "Pausing allocations for structural redefinition.";
- paused_ = true;
- AllocationManager::Get()->PauseAllocations(art::Thread::Current());
- // Collect garbage so we don't need to recreate as much.
- runtime->GetHeap()->CollectGarbage(/*clear_soft_references=*/false);
- }
- }
-
- ~ScopedSuspendAllocations() REQUIRES_SHARED(art::Locks::mutator_lock_) {
- if (paused_) {
- AllocationManager::Get()->ResumeAllocations(art::Thread::Current());
- }
- }
-
- private:
- bool paused_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedSuspendAllocations);
-};
-
jvmtiError Redefiner::Run() {
art::StackHandleScope<1> hs(self_);
// Allocate an array to hold onto all java temporary objects associated with this redefinition.
@@ -2043,11 +1873,6 @@
return result_;
}
- ScopedSuspendAllocations suspend_alloc(runtime_, holder);
- if (!CollectAndCreateNewInstances(holder)) {
- return result_;
- }
-
// At this point we can no longer fail without corrupting the runtime state.
for (RedefinitionDataIter data = holder.begin(); data != holder.end(); ++data) {
art::ClassLinker* cl = runtime_->GetClassLinker();
@@ -2198,120 +2023,6 @@
}
}
-static void CopyField(art::ObjPtr<art::mirror::Object> target,
- art::ArtField* new_field,
- art::ObjPtr<art::mirror::Object> source,
- art::ArtField& old_field) REQUIRES(art::Locks::mutator_lock_) {
- art::Primitive::Type ftype = old_field.GetTypeAsPrimitiveType();
- CHECK_EQ(ftype, new_field->GetTypeAsPrimitiveType())
- << old_field.PrettyField() << " vs " << new_field->PrettyField();
- if (ftype == art::Primitive::kPrimNot) {
- new_field->SetObject<false>(target, old_field.GetObject(source));
- } else {
- switch (ftype) {
-#define UPDATE_FIELD(TYPE) \
- case art::Primitive::kPrim##TYPE: \
- new_field->Set##TYPE<false>(target, old_field.Get##TYPE(source)); \
- break
- UPDATE_FIELD(Int);
- UPDATE_FIELD(Float);
- UPDATE_FIELD(Long);
- UPDATE_FIELD(Double);
- UPDATE_FIELD(Short);
- UPDATE_FIELD(Char);
- UPDATE_FIELD(Byte);
- UPDATE_FIELD(Boolean);
- case art::Primitive::kPrimNot:
- case art::Primitive::kPrimVoid:
- LOG(FATAL) << "Unexpected field with type " << ftype << " found!";
- UNREACHABLE();
-#undef UPDATE_FIELD
- }
- }
-}
-
-static void CopyFields(bool is_static,
- art::ObjPtr<art::mirror::Object> target,
- art::ObjPtr<art::mirror::Class> target_class,
- art::ObjPtr<art::mirror::Object> source,
- art::ObjPtr<art::mirror::Class> source_class)
- REQUIRES(art::Locks::mutator_lock_) {
- DCHECK(!source_class->IsObjectClass() && !target_class->IsObjectClass())
- << "Should not be overriding object class fields. Target: " << target_class->PrettyClass()
- << " Source: " << source_class->PrettyClass();
- for (art::ArtField& f : (is_static ? source_class->GetSFields() : source_class->GetIFields())) {
- art::ArtField* new_field =
- (is_static ? target_class->FindDeclaredStaticField(f.GetName(), f.GetTypeDescriptor())
- : target_class->FindDeclaredInstanceField(f.GetName(), f.GetTypeDescriptor()));
- CHECK(new_field != nullptr) << "could not find new version of " << f.PrettyField();
- CopyField(target, new_field, source, f);
- }
- if (!is_static && !target_class->GetSuperClass()->IsObjectClass()) {
- CopyFields(
- is_static, target, target_class->GetSuperClass(), source, source_class->GetSuperClass());
- }
-}
-
-static void ClearField(art::ObjPtr<art::mirror::Object> target, art::ArtField& field)
- REQUIRES(art::Locks::mutator_lock_) {
- art::Primitive::Type ftype = field.GetTypeAsPrimitiveType();
- if (ftype == art::Primitive::kPrimNot) {
- field.SetObject<false>(target, nullptr);
- } else {
- switch (ftype) {
-#define UPDATE_FIELD(TYPE) \
- case art::Primitive::kPrim##TYPE: \
- field.Set##TYPE<false>(target, 0); \
- break
- UPDATE_FIELD(Int);
- UPDATE_FIELD(Float);
- UPDATE_FIELD(Long);
- UPDATE_FIELD(Double);
- UPDATE_FIELD(Short);
- UPDATE_FIELD(Char);
- UPDATE_FIELD(Byte);
- UPDATE_FIELD(Boolean);
- case art::Primitive::kPrimNot:
- case art::Primitive::kPrimVoid:
- LOG(FATAL) << "Unexpected field with type " << ftype << " found!";
- UNREACHABLE();
-#undef UPDATE_FIELD
- }
- }
-}
-
-static void ClearFields(bool is_static,
- art::ObjPtr<art::mirror::Object> target,
- art::ObjPtr<art::mirror::Class> target_class)
- REQUIRES(art::Locks::mutator_lock_) {
- DCHECK(!target_class->IsObjectClass());
- for (art::ArtField& f : (is_static ? target_class->GetSFields() : target_class->GetIFields())) {
- ClearField(target, f);
- }
- if (!is_static && !target_class->GetSuperClass()->IsObjectClass()) {
- ClearFields(is_static, target, target_class->GetSuperClass());
- }
-}
-
-static void CopyAndClearFields(bool is_static,
- art::ObjPtr<art::mirror::Object> target,
- art::ObjPtr<art::mirror::Class> target_class,
- art::ObjPtr<art::mirror::Object> source,
- art::ObjPtr<art::mirror::Class> source_class)
- REQUIRES(art::Locks::mutator_lock_) {
- // Copy all non-j.l.Object fields
- CopyFields(is_static, target, target_class, source, source_class);
- // Copy the lock-word.
- target->SetLockWord(source->GetLockWord(false), false);
- // Clear (reset) the old one.
- source->SetLockWord(art::LockWord::Default(), false);
- art::WriteBarrier::ForEveryFieldWrite(target);
-
- // Clear the fields from the old class. We don't need it anymore.
- ClearFields(is_static, source, source_class);
- art::WriteBarrier::ForEveryFieldWrite(source);
-}
-
void Redefiner::ClassRedefinition::UpdateClassStructurally(const RedefinitionDataIter& holder) {
DCHECK(IsStructuralRedefinition());
// LETS GO. We've got all new class structures so no need to do all the updating of the stacks.
@@ -2325,24 +2036,40 @@
std::map<art::ArtMethod*, art::ArtMethod*> method_map;
std::map<art::ArtField*, art::ArtField*> field_map;
CollectNewFieldAndMethodMappings(holder, &method_map, &field_map);
- art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> new_instances(
- holder.GetNewInstanceObjects());
- art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> old_instances(
- holder.GetOldInstanceObjects());
+ // Copy over the fields of the object.
CHECK(!orig.IsNull());
CHECK(!replacement.IsNull());
- // Copy over the static fields of the class and all the instance fields.
- CopyAndClearFields(/*is_static=*/true, replacement, replacement, orig, orig);
+ for (art::ArtField& f : orig->GetSFields()) {
+ art::ArtField* new_field =
+ replacement->FindDeclaredStaticField(f.GetName(), f.GetTypeDescriptor());
+ CHECK(new_field != nullptr) << "could not find new version of " << f.PrettyField();
+ art::Primitive::Type ftype = f.GetTypeAsPrimitiveType();
+ CHECK_EQ(ftype, new_field->GetTypeAsPrimitiveType())
+ << f.PrettyField() << " vs " << new_field->PrettyField();
+ if (ftype == art::Primitive::kPrimNot) {
+ new_field->SetObject<false>(replacement, f.GetObject(orig));
+ } else {
+ switch (ftype) {
+#define UPDATE_FIELD(TYPE) \
+ case art::Primitive::kPrim##TYPE: \
+ new_field->Set##TYPE<false>(replacement, f.Get##TYPE(orig)); \
+ break
- // Copy and clear the fields of the old-instances.
- for (int32_t i = 0; i < old_instances->GetLength(); i++) {
- art::ObjPtr<art::mirror::Object> old_instance(old_instances->Get(i));
- art::ObjPtr<art::mirror::Object> new_instance(new_instances->Get(i));
- CopyAndClearFields(/*is_static=*/false,
- new_instance,
- new_instance->GetClass(),
- old_instance,
- old_instance->GetClass());
+ UPDATE_FIELD(Int);
+ UPDATE_FIELD(Float);
+ UPDATE_FIELD(Long);
+ UPDATE_FIELD(Double);
+ UPDATE_FIELD(Short);
+ UPDATE_FIELD(Char);
+ UPDATE_FIELD(Byte);
+ UPDATE_FIELD(Boolean);
+ case art::Primitive::kPrimNot:
+ case art::Primitive::kPrimVoid:
+ LOG(FATAL) << "Unexpected field with type " << ftype << " found!";
+ UNREACHABLE();
+#undef UPDATE_FIELD
+ }
+ }
}
// Mark old class obsolete.
orig->SetObsoleteObject();
@@ -2352,6 +2079,9 @@
m.SetDontCompile();
DCHECK_EQ(orig, m.GetDeclaringClass());
}
+ // Copy the lock-word
+ replacement->SetLockWord(orig->GetLockWord(false), false);
+ orig->SetLockWord(art::LockWord::Default(), false);
// Update live pointers in ART code.
auto could_change_resolution_of = [&](auto* field_or_method,
const auto& info) REQUIRES(art::Locks::mutator_lock_) {
@@ -2436,23 +2166,39 @@
// Force every frame of every thread to deoptimize (any frame might have eg offsets compiled in).
driver_->runtime_->GetInstrumentation()->DeoptimizeAllThreadFrames();
- std::unordered_map<art::ObjPtr<art::mirror::Object>,
- art::ObjPtr<art::mirror::Object>,
- art::HashObjPtr> map;
- map.emplace(orig, replacement);
- for (int32_t i = 0; i < old_instances->GetLength(); i++) {
- map.emplace(old_instances->Get(i), new_instances->Get(i));
- }
-
- // Actually perform the general replacement. This doesn't affect ArtMethod/ArtFields. It does
- // affect the declaring_class field of all the obsolete objects, which is unfortunate and needs to
- // be undone. This replaces the mirror::Class in 'holder' as well. It's magic!
- HeapExtensions::ReplaceReferences(driver_->self_, map);
+ // Actually perform the general replacement. This doesn't affect ArtMethod/ArtFields.
+ // This replaces the mirror::Class in 'holder' as well. It's magic!
+ HeapExtensions::ReplaceReference(driver_->self_, orig, replacement);
// Save the old class so that the JIT gc doesn't get confused by it being collected before the
// jit code. This is also needed to keep the dex-caches of any obsolete methods live.
replacement->GetExtData()->SetObsoleteClass(orig);
+ // Clear the static fields of the old-class.
+ for (art::ArtField& f : orig->GetSFields()) {
+ switch (f.GetTypeAsPrimitiveType()) {
+ #define UPDATE_FIELD(TYPE) \
+ case art::Primitive::kPrim ## TYPE: \
+ f.Set ## TYPE <false>(orig, 0); \
+ break
+
+ UPDATE_FIELD(Int);
+ UPDATE_FIELD(Float);
+ UPDATE_FIELD(Long);
+ UPDATE_FIELD(Double);
+ UPDATE_FIELD(Short);
+ UPDATE_FIELD(Char);
+ UPDATE_FIELD(Byte);
+ UPDATE_FIELD(Boolean);
+ case art::Primitive::kPrimNot:
+ f.SetObject<false>(orig, nullptr);
+ break;
+ case art::Primitive::kPrimVoid:
+ LOG(FATAL) << "Unexpected field with type void found!";
+ UNREACHABLE();
+ #undef UPDATE_FIELD
+ }
+ }
art::jit::Jit* jit = driver_->runtime_->GetJit();
if (jit != nullptr) {
diff --git a/openjdkjvmti/ti_redefine.h b/openjdkjvmti/ti_redefine.h
index cedce92..58a688c 100644
--- a/openjdkjvmti/ti_redefine.h
+++ b/openjdkjvmti/ti_redefine.h
@@ -41,7 +41,6 @@
#include "art_jvmti.h"
#include "base/array_ref.h"
#include "base/globals.h"
-#include "dex/class_accessor.h"
#include "dex/dex_file.h"
#include "dex/dex_file_structs.h"
#include "jni/jni_env_ext-inl.h"
@@ -156,9 +155,6 @@
bool FinishRemainingAllocations(/*out*/RedefinitionDataIter* cur_data)
REQUIRES_SHARED(art::Locks::mutator_lock_);
- bool CollectAndCreateNewInstances(/*out*/RedefinitionDataIter* cur_data)
- REQUIRES_SHARED(art::Locks::mutator_lock_);
-
bool AllocateAndRememberNewDexFileCookie(
art::Handle<art::mirror::ClassLoader> source_class_loader,
art::Handle<art::mirror::Object> dex_file_obj,
@@ -238,14 +234,8 @@
void RecordNewMethodAdded();
void RecordNewFieldAdded();
- void RecordHasVirtualMembers() {
- has_virtuals_ = true;
- }
- bool HasVirtualMembers() const {
- return has_virtuals_;
- }
-
+ private:
bool IsStructuralRedefinition() const {
DCHECK(!(added_fields_ || added_methods_) || driver_->IsStructuralRedefinition())
<< "added_fields_: " << added_fields_ << " added_methods_: " << added_methods_
@@ -253,7 +243,6 @@
return driver_->IsStructuralRedefinition() && (added_fields_ || added_methods_);
}
- private:
void UpdateClassStructurally(const RedefinitionDataIter& cur_data)
REQUIRES(art::Locks::mutator_lock_);
@@ -268,7 +257,6 @@
bool added_fields_ = false;
bool added_methods_ = false;
- bool has_virtuals_ = false;
// Does the class need to be reverified due to verification soft-fails possibly forcing
// interpreter or lock-counting?
@@ -323,8 +311,6 @@
REQUIRES_SHARED(art::Locks::mutator_lock_);
bool FinishAllRemainingAllocations(RedefinitionDataHolder& holder)
REQUIRES_SHARED(art::Locks::mutator_lock_);
- bool CollectAndCreateNewInstances(RedefinitionDataHolder& holder)
- REQUIRES_SHARED(art::Locks::mutator_lock_);
void ReleaseAllDexFiles() REQUIRES_SHARED(art::Locks::mutator_lock_);
void ReverifyClasses(RedefinitionDataHolder& holder) REQUIRES_SHARED(art::Locks::mutator_lock_);
void UnregisterAllBreakpoints() REQUIRES_SHARED(art::Locks::mutator_lock_);
diff --git a/runtime/base/locks.h b/runtime/base/locks.h
index c3518f3..4b85df0 100644
--- a/runtime/base/locks.h
+++ b/runtime/base/locks.h
@@ -129,9 +129,6 @@
kMutatorLock,
kInstrumentEntrypointsLock,
- // This is a generic lock level for a top-level lock meant to be gained after having the
- // UserCodeSuspensionLock.
- kPostUserCodeSuspensionTopLevelLock,
kUserCodeSuspensionLock,
kZygoteCreationLock,
diff --git a/runtime/gc/allocation_listener.h b/runtime/gc/allocation_listener.h
index 376b524..a578252 100644
--- a/runtime/gc/allocation_listener.h
+++ b/runtime/gc/allocation_listener.h
@@ -23,13 +23,11 @@
#include "base/locks.h"
#include "base/macros.h"
#include "gc_root.h"
-#include "handle.h"
#include "obj_ptr.h"
namespace art {
namespace mirror {
-class Class;
class Object;
} // namespace mirror
@@ -41,26 +39,6 @@
public:
virtual ~AllocationListener() {}
- // An event to allow a listener to intercept and modify an allocation before it takes place.
- // The listener can change the byte_count and type as they see fit. Extreme caution should be used
- // when doing so. This can also be used to control allocation occurring on another thread.
- //
- // Concurrency guarantees: This might be called multiple times for each single allocation. It's
- // guaranteed that, between the final call to the callback and the object being visible to
- // heap-walks there are no suspensions. If a suspension was allowed between these events the
- // callback will be invoked again after passing the suspend point.
- //
- // If the alloc succeeds it is guaranteed there are no suspend-points between the last return of
- // PreObjectAlloc and the newly allocated object being visible to heap-walks.
- //
- // This can also be used to make any last-minute changes to the type or size of the allocation.
- virtual void PreObjectAllocated(Thread* self ATTRIBUTE_UNUSED,
- MutableHandle<mirror::Class> type ATTRIBUTE_UNUSED,
- size_t* byte_count ATTRIBUTE_UNUSED)
- REQUIRES(!Roles::uninterruptible_) REQUIRES_SHARED(Locks::mutator_lock_) {}
- // Fast check if we want to get the PreObjectAllocated callback, to avoid the expense of creating
- // handles. Defaults to false.
- virtual bool HasPreAlloc() const { return false; }
virtual void ObjectAllocated(Thread* self, ObjPtr<mirror::Object>* obj, size_t byte_count)
REQUIRES_SHARED(Locks::mutator_lock_) = 0;
};
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 04632ef..c1b3a63 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -65,30 +65,10 @@
HandleWrapperObjPtr<mirror::Class> h = hs.NewHandleWrapper(&klass);
self->PoisonObjectPointers();
}
- auto send_pre_object_allocated = [&]() REQUIRES_SHARED(Locks::mutator_lock_)
- ACQUIRE(Roles::uninterruptible_) {
- if constexpr (kInstrumented) {
- AllocationListener* l = nullptr;
- l = alloc_listener_.load(std::memory_order_seq_cst);
- if (UNLIKELY(l != nullptr) && UNLIKELY(l->HasPreAlloc())) {
- StackHandleScope<1> hs(self);
- HandleWrapperObjPtr<mirror::Class> h_klass(hs.NewHandleWrapper(&klass));
- l->PreObjectAllocated(self, h_klass, &byte_count);
- }
- }
- return self->StartAssertNoThreadSuspension("Called PreObjectAllocated, no suspend until alloc");
- };
- // Do the initial pre-alloc
- const char* old_cause = send_pre_object_allocated();
- // We shouldn't have any NoThreadSuspension here!
- DCHECK(old_cause == nullptr) << old_cause;
-
// Need to check that we aren't the large object allocator since the large object allocation code
// path includes this function. If we didn't check we would have an infinite loop.
ObjPtr<mirror::Object> obj;
if (kCheckLargeObject && UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) {
- // AllocLargeObject can suspend and will recall PreObjectAllocated if needed.
- self->EndAssertNoThreadSuspension(old_cause);
obj = AllocLargeObject<kInstrumented, PreFenceVisitor>(self, &klass, byte_count,
pre_fence_visitor);
if (obj != nullptr) {
@@ -100,8 +80,6 @@
// If the large object allocation failed, try to use the normal spaces (main space,
// non moving space). This can happen if there is significant virtual address space
// fragmentation.
- // We need to send the PreObjectAllocated again, we might have suspended during our failure.
- old_cause = send_pre_object_allocated();
}
// bytes allocated for the (individual) object.
size_t bytes_allocated;
@@ -122,7 +100,6 @@
usable_size = bytes_allocated;
no_suspend_pre_fence_visitor(obj, usable_size);
QuasiAtomic::ThreadFenceForConstructor();
- self->EndAssertNoThreadSuspension(old_cause);
} else if (
!kInstrumented && allocator == kAllocatorTypeRosAlloc &&
(obj = rosalloc_space_->AllocThreadLocal(self, byte_count, &bytes_allocated)) != nullptr &&
@@ -135,7 +112,6 @@
usable_size = bytes_allocated;
no_suspend_pre_fence_visitor(obj, usable_size);
QuasiAtomic::ThreadFenceForConstructor();
- self->EndAssertNoThreadSuspension(old_cause);
} else {
// Bytes allocated that includes bulk thread-local buffer allocations in addition to direct
// non-TLAB object allocations.
@@ -145,19 +121,14 @@
if (UNLIKELY(obj == nullptr)) {
// AllocateInternalWithGc can cause thread suspension, if someone instruments the entrypoints
// or changes the allocator in a suspend point here, we need to retry the allocation.
- // It will send the pre-alloc event again.
- self->EndAssertNoThreadSuspension(old_cause);
obj = AllocateInternalWithGc(self,
allocator,
kInstrumented,
byte_count,
&bytes_allocated,
&usable_size,
- &bytes_tl_bulk_allocated,
- &klass,
- &old_cause);
+ &bytes_tl_bulk_allocated, &klass);
if (obj == nullptr) {
- self->EndAssertNoThreadSuspension(old_cause);
// The only way that we can get a null return if there is no pending exception is if the
// allocator or instrumentation changed.
if (!self->IsExceptionPending()) {
@@ -185,7 +156,6 @@
}
no_suspend_pre_fence_visitor(obj, usable_size);
QuasiAtomic::ThreadFenceForConstructor();
- self->EndAssertNoThreadSuspension(old_cause);
if (bytes_tl_bulk_allocated > 0) {
size_t num_bytes_allocated_before =
num_bytes_allocated_.fetch_add(bytes_tl_bulk_allocated, std::memory_order_relaxed);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index a97ff98..85b79da 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -17,7 +17,6 @@
#include "heap.h"
#include <limits>
-#include "android-base/thread_annotations.h"
#if defined(__BIONIC__) || defined(__GLIBC__)
#include <malloc.h> // For mallinfo()
#endif
@@ -1724,37 +1723,11 @@
size_t* bytes_allocated,
size_t* usable_size,
size_t* bytes_tl_bulk_allocated,
- ObjPtr<mirror::Class>* klass,
- /*out*/const char** old_no_thread_suspend_cause) {
+ ObjPtr<mirror::Class>* klass) {
bool was_default_allocator = allocator == GetCurrentAllocator();
// Make sure there is no pending exception since we may need to throw an OOME.
self->AssertNoPendingException();
DCHECK(klass != nullptr);
- auto release_no_suspend = [&]() RELEASE(Roles::uninterruptible_) {
- self->EndAssertNoThreadSuspension(*old_no_thread_suspend_cause);
- };
- auto send_object_pre_alloc = [&]() ACQUIRE(Roles::uninterruptible_)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (UNLIKELY(instrumented)) {
- AllocationListener* l = nullptr;
- l = alloc_listener_.load(std::memory_order_seq_cst);
- if (UNLIKELY(l != nullptr) && UNLIKELY(l->HasPreAlloc())) {
- StackHandleScope<1> hs(self);
- HandleWrapperObjPtr<mirror::Class> h_klass(hs.NewHandleWrapper(klass));
- l->PreObjectAllocated(self, h_klass, &alloc_size);
- }
- }
- *old_no_thread_suspend_cause =
- self->StartAssertNoThreadSuspension("Called PreObjectAllocated, no suspend until alloc");
-};
-#define PERFORM_SUSPENDING_OPERATION(op) \
- [&]() REQUIRES(Roles::uninterruptible_) REQUIRES_SHARED(Locks::mutator_lock_) { \
- release_no_suspend(); \
- auto res = (op); \
- send_object_pre_alloc(); \
- return res; \
- }()
-
StackHandleScope<1> hs(self);
HandleWrapperObjPtr<mirror::Class> h(hs.NewHandleWrapper(klass));
// The allocation failed. If the GC is running, block until it completes, and then retry the
@@ -1762,8 +1735,6 @@
collector::GcType last_gc = WaitForGcToComplete(kGcCauseForAlloc, self);
// If we were the default allocator but the allocator changed while we were suspended,
// abort the allocation.
- // We just waited, call the pre-alloc again.
- send_object_pre_alloc();
if ((was_default_allocator && allocator != GetCurrentAllocator()) ||
(!instrumented && EntrypointsInstrumented())) {
return nullptr;
@@ -1778,9 +1749,8 @@
}
collector::GcType tried_type = next_gc_type_;
- const bool gc_ran = PERFORM_SUSPENDING_OPERATION(
- CollectGarbageInternal(tried_type, kGcCauseForAlloc, false) != collector::kGcTypeNone);
-
+ const bool gc_ran =
+ CollectGarbageInternal(tried_type, kGcCauseForAlloc, false) != collector::kGcTypeNone;
if ((was_default_allocator && allocator != GetCurrentAllocator()) ||
(!instrumented && EntrypointsInstrumented())) {
return nullptr;
@@ -1799,8 +1769,8 @@
continue;
}
// Attempt to run the collector, if we succeed, re-try the allocation.
- const bool plan_gc_ran = PERFORM_SUSPENDING_OPERATION(
- CollectGarbageInternal(gc_type, kGcCauseForAlloc, false) != collector::kGcTypeNone);
+ const bool plan_gc_ran =
+ CollectGarbageInternal(gc_type, kGcCauseForAlloc, false) != collector::kGcTypeNone;
if ((was_default_allocator && allocator != GetCurrentAllocator()) ||
(!instrumented && EntrypointsInstrumented())) {
return nullptr;
@@ -1830,7 +1800,7 @@
// TODO: Run finalization, but this may cause more allocations to occur.
// We don't need a WaitForGcToComplete here either.
DCHECK(!gc_plan_.empty());
- PERFORM_SUSPENDING_OPERATION(CollectGarbageInternal(gc_plan_.back(), kGcCauseForAlloc, true));
+ CollectGarbageInternal(gc_plan_.back(), kGcCauseForAlloc, true);
if ((was_default_allocator && allocator != GetCurrentAllocator()) ||
(!instrumented && EntrypointsInstrumented())) {
return nullptr;
@@ -1847,8 +1817,7 @@
current_time - last_time_homogeneous_space_compaction_by_oom_ >
min_interval_homogeneous_space_compaction_by_oom_) {
last_time_homogeneous_space_compaction_by_oom_ = current_time;
- HomogeneousSpaceCompactResult result =
- PERFORM_SUSPENDING_OPERATION(PerformHomogeneousSpaceCompact());
+ HomogeneousSpaceCompactResult result = PerformHomogeneousSpaceCompact();
// Thread suspension could have occurred.
if ((was_default_allocator && allocator != GetCurrentAllocator()) ||
(!instrumented && EntrypointsInstrumented())) {
@@ -1893,13 +1862,9 @@
}
}
}
-#undef PERFORM_SUSPENDING_OPERATION
// If the allocation hasn't succeeded by this point, throw an OOM error.
if (ptr == nullptr) {
- release_no_suspend();
ThrowOutOfMemoryError(self, alloc_size, allocator);
- *old_no_thread_suspend_cause =
- self->StartAssertNoThreadSuspension("Failed allocation fallback");
}
return ptr;
}
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 6f6cfd1..9ef6af5 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -1011,10 +1011,8 @@
size_t* bytes_allocated,
size_t* usable_size,
size_t* bytes_tl_bulk_allocated,
- ObjPtr<mirror::Class>* klass,
- /*out*/const char** old_no_thread_suspend_cause)
+ ObjPtr<mirror::Class>* klass)
REQUIRES(!Locks::thread_suspend_count_lock_, !*gc_complete_lock_, !*pending_task_lock_)
- ACQUIRE(Roles::uninterruptible_)
REQUIRES_SHARED(Locks::mutator_lock_);
// Allocate into a specific space.
diff --git a/runtime/offsets.h b/runtime/offsets.h
index 2f36fe6..6d1a8e0 100644
--- a/runtime/offsets.h
+++ b/runtime/offsets.h
@@ -37,9 +37,6 @@
constexpr size_t SizeValue() const {
return val_;
}
- constexpr bool operator==(Offset o) const {
- return SizeValue() == o.SizeValue();
- }
protected:
size_t val_;
diff --git a/test/1983-structural-redefinition-failures/expected.txt b/test/1983-structural-redefinition-failures/expected.txt
index 40a0914..54e1bcc 100644
--- a/test/1983-structural-redefinition-failures/expected.txt
+++ b/test/1983-structural-redefinition-failures/expected.txt
@@ -28,7 +28,7 @@
Is Structurally modifiable class java.util.Objects true
Is Structurally modifiable class java.util.Arrays true
Is Structurally modifiable class [Ljava.lang.Object; false
-Is Structurally modifiable class java.lang.Integer true
+Is Structurally modifiable class java.lang.Integer false
Is Structurally modifiable class java.lang.Number false
Is Structurally modifiable class art.Test1983$NoVirtuals true
Is Structurally modifiable class art.Test1983$WithVirtuals false
diff --git a/test/1994-final-virtual-structural/expected.txt b/test/1994-final-virtual-structural/expected.txt
deleted file mode 100644
index 9b74d30..0000000
--- a/test/1994-final-virtual-structural/expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Hi!
-Hello world!
-Hej Verden!
-Bonjour le monde!
-こんにちは世界!
diff --git a/test/1994-final-virtual-structural/info.txt b/test/1994-final-virtual-structural/info.txt
deleted file mode 100644
index 606c984..0000000
--- a/test/1994-final-virtual-structural/info.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests basic functions in the jvmti plugin.
-
-Tests that using the structural redefinition can add new virtual methods and fields.
diff --git a/test/1994-final-virtual-structural/run b/test/1994-final-virtual-structural/run
deleted file mode 100755
index 03e41a5..0000000
--- a/test/1994-final-virtual-structural/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-./default-run "$@" --jvmti --runtime-option -Xopaque-jni-ids:true
diff --git a/test/1994-final-virtual-structural/src/Main.java b/test/1994-final-virtual-structural/src/Main.java
deleted file mode 100644
index 3f0cb14..0000000
--- a/test/1994-final-virtual-structural/src/Main.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-public class Main {
- public static void main(String[] args) throws Exception {
- art.Test1994.run();
- }
-}
diff --git a/test/1994-final-virtual-structural/src/art/Redefinition.java b/test/1994-final-virtual-structural/src/art/Redefinition.java
deleted file mode 120000
index 81eaf31..0000000
--- a/test/1994-final-virtual-structural/src/art/Redefinition.java
+++ /dev/null
@@ -1 +0,0 @@
-../../../jvmti-common/Redefinition.java
\ No newline at end of file
diff --git a/test/1994-final-virtual-structural/src/art/Test1994.java b/test/1994-final-virtual-structural/src/art/Test1994.java
deleted file mode 100644
index 9ae7772..0000000
--- a/test/1994-final-virtual-structural/src/art/Test1994.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.
- */
-
-package art;
-
-import java.util.Base64;
-public class Test1994 {
-
- public static final class Transform {
- public void sayHi() {
- System.out.println("Hi!");
- }
- }
-
- /**
- * base64 encoded class/dex file for
- * public static final class Transform {
- * public void sayHi() {
- * sayHiEnglish();
- * sayHiDanish();
- * sayHiFrance();
- * sayHiJapan();
- * }
- * public void sayHiEnglish() {
- * System.out.println("Hello world!");
- * }
- * public void sayHiDanish() {
- * System.out.println("Hej Verden!");
- * }
- * public void sayHiJapan() {
- * System.out.println("こんにちは世界!");
- * }
- * public void sayHiFrance() {
- * System.out.println("Bonjour le monde!");
- * }
- * }
- */
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQA87tn3VIDgMrF+Md2W4r58elaMPcSfk2CMBQAAcAAAAHhWNBIAAAAAAAAAAMgEAAAc" +
- "AAAAcAAAAAkAAADgAAAAAgAAAAQBAAABAAAAHAEAAAgAAAAkAQAAAQAAAGQBAAAIBAAAhAEAAG4C" +
- "AAB2AgAAiQIAAJYCAACkAgAAvgIAAM4CAADyAgAAEgMAACkDAAA9AwAAUQMAAGUDAAB0AwAAfwMA" +
- "AIIDAACGAwAAkwMAAJkDAACeAwAApwMAAK4DAAC7AwAAyQMAANYDAADiAwAA6QMAAGEEAAAEAAAA" +
- "BQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAA4AAAAOAAAACAAAAAAAAAAPAAAACAAAAGgCAAAH" +
- "AAQAEgAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFQAAAAAAAAAWAAAAAAAAABcAAAAAAAAAGAAAAAQA" +
- "AQATAAAABQAAAAAAAAAAAAAAEQAAAAUAAAAAAAAADAAAALgEAACIBAAAAAAAAAEAAQABAAAASAIA" +
- "AAQAAABwEAcAAAAOAAEAAQABAAAATAIAAA0AAABuEAMAAABuEAIAAABuEAQAAABuEAUAAAAOAAAA" +
- "AwABAAIAAABUAgAACAAAAGIAAAAaAQIAbiAGABAADgADAAEAAgAAAFkCAAAIAAAAYgAAABoBAwBu" +
- "IAYAEAAOAAMAAQACAAAAXgIAAAgAAABiAAAAGgEBAG4gBgAQAA4AAwABAAIAAABjAgAACAAAAGIA" +
- "AAAaARsAbiAGABAADgADAA4ABQAOPDw8PAAOAA54AAsADngAFAAOeAARAA54AAEAAAAGAAY8aW5p" +
- "dD4AEUJvbmpvdXIgbGUgbW9uZGUhAAtIZWogVmVyZGVuIQAMSGVsbG8gd29ybGQhABhMYXJ0L1Rl" +
- "c3QxOTk0JFRyYW5zZm9ybTsADkxhcnQvVGVzdDE5OTQ7ACJMZGFsdmlrL2Fubm90YXRpb24vRW5j" +
- "bG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJDbGFzczsAFUxqYXZhL2lvL1By" +
- "aW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZh" +
- "L2xhbmcvU3lzdGVtOwANVGVzdDE5OTQuamF2YQAJVHJhbnNmb3JtAAFWAAJWTAALYWNjZXNzRmxh" +
- "Z3MABG5hbWUAA291dAAHcHJpbnRsbgAFc2F5SGkAC3NheUhpRGFuaXNoAAxzYXlIaUVuZ2xpc2gA" +
- "C3NheUhpRnJhbmNlAApzYXlIaUphcGFuAAV2YWx1ZQB2fn5EOHsiY29tcGlsYXRpb24tbW9kZSI6" +
- "ImRlYnVnIiwibWluLWFwaSI6MSwic2hhLTEiOiJjZDkwMDIzOTMwZDk3M2Y1NzcxMWYxZDRmZGFh" +
- "ZDdhM2U0NzE0NjM3IiwidmVyc2lvbiI6IjEuNy4xNC1kZXYifQAI44GT44KT44Gr44Gh44Gv5LiW" +
- "55WMIQACAgEZGAECAwIQBBkRFw0AAAEFAIGABIQDAQGcAwEByAMBAegDAQGIBAEBqAQAAAAAAAAC" +
- "AAAAeQQAAH8EAACsBAAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAcAAAAcAAAAAIA" +
- "AAAJAAAA4AAAAAMAAAACAAAABAEAAAQAAAABAAAAHAEAAAUAAAAIAAAAJAEAAAYAAAABAAAAZAEA" +
- "AAEgAAAGAAAAhAEAAAMgAAAGAAAASAIAAAEQAAABAAAAaAIAAAIgAAAcAAAAbgIAAAQgAAACAAAA" +
- "eQQAAAAgAAABAAAAiAQAAAMQAAACAAAAqAQAAAYgAAABAAAAuAQAAAAQAAABAAAAyAQAAA==");
-
- public static void run() {
- Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
- doTest(new Transform());
- }
-
- public static void doTest(Transform t) {
- t.sayHi();
- Redefinition.doCommonStructuralClassRedefinition(Transform.class, DEX_BYTES);
- t.sayHi();
- }
-}
diff --git a/test/1995-final-virtual-structural-multithread/expected.txt b/test/1995-final-virtual-structural-multithread/expected.txt
deleted file mode 100644
index e69de29..0000000
--- a/test/1995-final-virtual-structural-multithread/expected.txt
+++ /dev/null
diff --git a/test/1995-final-virtual-structural-multithread/info.txt b/test/1995-final-virtual-structural-multithread/info.txt
deleted file mode 100644
index f9b7bdd..0000000
--- a/test/1995-final-virtual-structural-multithread/info.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Tests structural redefinition with multiple threads.
-
-Tests that using the structural redefinition while concurrently using the class being redefined
-doesn't cause any unexpected problems.
diff --git a/test/1995-final-virtual-structural-multithread/run b/test/1995-final-virtual-structural-multithread/run
deleted file mode 100755
index 421f7b0..0000000
--- a/test/1995-final-virtual-structural-multithread/run
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-# TODO(b/144168550) This test uses access patterns that can be replaced by
-# iget-object-quick during dex2dex compilation. This breaks the test since the
-# -quick opcode encodes the exact byte offset of fields. Since this test changes
-# the offset this causes problems.
-./default-run "$@" --jvmti --runtime-option -Xopaque-jni-ids:true -Xcompiler-option --debuggable
diff --git a/test/1995-final-virtual-structural-multithread/src/Main.java b/test/1995-final-virtual-structural-multithread/src/Main.java
deleted file mode 100644
index f19358d..0000000
--- a/test/1995-final-virtual-structural-multithread/src/Main.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-public class Main {
- public static void main(String[] args) throws Exception {
- art.Test1995.run();
- }
-}
diff --git a/test/1995-final-virtual-structural-multithread/src/art/Redefinition.java b/test/1995-final-virtual-structural-multithread/src/art/Redefinition.java
deleted file mode 120000
index 81eaf31..0000000
--- a/test/1995-final-virtual-structural-multithread/src/art/Redefinition.java
+++ /dev/null
@@ -1 +0,0 @@
-../../../jvmti-common/Redefinition.java
\ No newline at end of file
diff --git a/test/1995-final-virtual-structural-multithread/src/art/Test1995.java b/test/1995-final-virtual-structural-multithread/src/art/Test1995.java
deleted file mode 100644
index 1ffee60..0000000
--- a/test/1995-final-virtual-structural-multithread/src/art/Test1995.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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.
- */
-
-package art;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.concurrent.CountDownLatch;
-public class Test1995 {
- private static final int NUM_THREADS = 20;
-
- public static final class Transform {
- public String greetingEnglish;
- public Transform() {
- this.greetingEnglish = "Hello";
- }
- public String sayHi() {
- return greetingEnglish + " from " + Thread.currentThread().getName();
- }
- }
-
- /**
- * base64 encoded class/dex file for
- * public static final class Transform {
- * public String greetingEnglish;
- * public String greetingFrench;
- * public String greetingDanish;
- * public String greetingJapanese;
- *
- * public Transform() {
- * this.greetingEnglish = "Hello World";
- * this.greetingFrench = "Bonjour le Monde";
- * this.greetingDanish = "Hej Verden";
- * this.greetingJapanese = "こんにちは世界";
- * }
- * public String sayHi() {
- * return sayHiEnglish() + ", " + sayHiFrench() + ", " + sayHiDanish() + ", " + sayHiJapanese() + " from " + Thread.currentThread().getName();
- * }
- * public String sayHiEnglish() {
- * return greetingEnglish;
- * }
- * public String sayHiDanish() {
- * return greetingDanish;
- * }
- * public String sayHiJapanese() {
- * return greetingJapanese;
- * }
- * public String sayHiFrench() {
- * return greetingFrench;
- * }
- * }
- */
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
-"ZGV4CjAzNQCsHrUqkb8cYgT2oYN7HlVbeOxJT/kONRvgBgAAcAAAAHhWNBIAAAAAAAAAABwGAAAl" +
-"AAAAcAAAAAkAAAAEAQAABAAAACgBAAAEAAAAWAEAAAwAAAB4AQAAAQAAANgBAADoBAAA+AEAAEoD" +
-"AABSAwAAVgMAAF4DAABwAwAAfAMAAIkDAACMAwAAkAMAAKoDAAC6AwAA3gMAAP4DAAASBAAAJgQA" +
-"AEEEAABVBAAAZAQAAG8EAAByBAAAfwQAAIcEAACWBAAAnwQAAK8EAADABAAA0AQAAOIEAADoBAAA" +
-"7wQAAPwEAAAKBQAAFwUAACYFAAAwBQAANwUAAK8FAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAO" +
-"AAAADwAAABIAAAAGAAAABQAAAAAAAAAHAAAABgAAAEQDAAAGAAAABwAAAAAAAAASAAAACAAAAAAA" +
-"AAAAAAUAFwAAAAAABQAYAAAAAAAFABkAAAAAAAUAGgAAAAAAAwACAAAAAAAAABwAAAAAAAAAHQAA" +
-"AAAAAAAeAAAAAAAAAB8AAAAAAAAAIAAAAAQAAwACAAAABgADAAIAAAAGAAEAFAAAAAYAAAAhAAAA" +
-"BwACABUAAAAHAAAAFgAAAAAAAAARAAAABAAAAAAAAAAQAAAADAYAANUFAAAAAAAABwABAAIAAAAt" +
-"AwAAQQAAAG4QAwAGAAwAbhAEAAYADAFuEAIABgAMAm4QBQAGAAwDcQAKAAAADARuEAsABAAMBCIF" +
-"BgBwEAcABQBuIAgABQAaAAEAbiAIAAUAbiAIABUAbiAIAAUAbiAIACUAbiAIAAUAbiAIADUAGgAA" +
-"AG4gCAAFAG4gCABFAG4QCQAFAAwAEQAAAAIAAQAAAAAAMQMAAAMAAABUEAAAEQAAAAIAAQAAAAAA" +
-"NQMAAAMAAABUEAEAEQAAAAIAAQAAAAAAOQMAAAMAAABUEAIAEQAAAAIAAQAAAAAAPQMAAAMAAABU" +
-"EAMAEQAAAAIAAQABAAAAJAMAABQAAABwEAYAAQAaAAUAWxABABoAAwBbEAIAGgAEAFsQAAAaACQA" +
-"WxADAA4ACQAOPEtLS0sAEAAOABYADgATAA4AHAAOABkADgAAAAABAAAABQAGIGZyb20gAAIsIAAG" +
-"PGluaXQ+ABBCb25qb3VyIGxlIE1vbmRlAApIZWogVmVyZGVuAAtIZWxsbyBXb3JsZAABTAACTEwA" +
-"GExhcnQvVGVzdDE5OTUkVHJhbnNmb3JtOwAOTGFydC9UZXN0MTk5NTsAIkxkYWx2aWsvYW5ub3Rh" +
-"dGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwASTGph" +
-"dmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAGUxqYXZhL2xhbmcvU3RyaW5nQnVp" +
-"bGRlcjsAEkxqYXZhL2xhbmcvVGhyZWFkOwANVGVzdDE5OTUuamF2YQAJVHJhbnNmb3JtAAFWAAth" +
-"Y2Nlc3NGbGFncwAGYXBwZW5kAA1jdXJyZW50VGhyZWFkAAdnZXROYW1lAA5ncmVldGluZ0Rhbmlz" +
-"aAAPZ3JlZXRpbmdFbmdsaXNoAA5ncmVldGluZ0ZyZW5jaAAQZ3JlZXRpbmdKYXBhbmVzZQAEbmFt" +
-"ZQAFc2F5SGkAC3NheUhpRGFuaXNoAAxzYXlIaUVuZ2xpc2gAC3NheUhpRnJlbmNoAA1zYXlIaUph" +
-"cGFuZXNlAAh0b1N0cmluZwAFdmFsdWUAdn5+RDh7ImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1ZyIs" +
-"Im1pbi1hcGkiOjEsInNoYS0xIjoiNjBkYTRkNjdiMzgxYzQyNDY3NzU3YzQ5ZmI2ZTU1NzU2ZDg4" +
-"YTJmMyIsInZlcnNpb24iOiIxLjcuMTItZGV2In0AB+OBk+OCk+OBq+OBoeOBr+S4lueVjAACAgEi" +
-"GAECAwITBBkbFxEABAEFAAEBAQEBAQEAgYAE7AUBAfgDAQGMBQEBpAUBAbwFAQHUBQAAAAAAAgAA" +
-"AMYFAADMBQAAAAYAAAAAAAAAAAAAAAAAABAAAAAAAAAAAQAAAAAAAAABAAAAJQAAAHAAAAACAAAA" +
-"CQAAAAQBAAADAAAABAAAACgBAAAEAAAABAAAAFgBAAAFAAAADAAAAHgBAAAGAAAAAQAAANgBAAAB" +
-"IAAABgAAAPgBAAADIAAABgAAACQDAAABEAAAAQAAAEQDAAACIAAAJQAAAEoDAAAEIAAAAgAAAMYF" +
-"AAAAIAAAAQAAANUFAAADEAAAAgAAAPwFAAAGIAAAAQAAAAwGAAAAEAAAAQAAABwGAAA=");
-
-
- public static void run() throws Exception {
- Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
- doTest();
- }
-
- public static final class MyThread extends Thread {
- public MyThread(CountDownLatch delay, int id) {
- super("Thread: " + id);
- this.thr_id = id;
- this.results = new ArrayList<>(1000);
- this.finish = false;
- this.delay = delay;
- }
-
- public void run() {
- delay.countDown();
- while (!finish) {
- Transform t = new Transform();
- results.add(t.sayHi());
- }
- }
-
- public void finish() throws Exception {
- finish = true;
- this.join();
- }
-
- public void Check() throws Exception {
- for (String s : results) {
- if (!s.equals("Hello from " + getName()) &&
- !s.equals("Hello, null, null, null from " + getName()) &&
- !s.equals("Hello World, Bonjour le Monde, Hej Verden, こんにちは世界 from " + getName())) {
- System.out.println("FAIL " + thr_id + ": Unexpected result: " + s);
- }
- }
- }
-
- public ArrayList<String> results;
- public volatile boolean finish;
- public int thr_id;
- public CountDownLatch delay;
- }
-
- public static MyThread[] startThreads(int num_threads) throws Exception {
- CountDownLatch cdl = new CountDownLatch(num_threads);
- MyThread[] res = new MyThread[num_threads];
- for (int i = 0; i < num_threads; i++) {
- res[i] = new MyThread(cdl, i);
- res[i].start();
- }
- cdl.await();
- return res;
- }
- public static void finishThreads(MyThread[] thrs) throws Exception {
- for (MyThread t : thrs) {
- t.finish();
- }
- for (MyThread t : thrs) {
- t.Check();
- }
- }
-
- public static void doTest() throws Exception {
- MyThread[] threads = startThreads(NUM_THREADS);
- Redefinition.doCommonStructuralClassRedefinition(Transform.class, DEX_BYTES);
- finishThreads(threads);
- }
-}
diff --git a/test/1996-final-override-virtual-structural/expected.txt b/test/1996-final-override-virtual-structural/expected.txt
deleted file mode 100644
index 20cd98f..0000000
--- a/test/1996-final-override-virtual-structural/expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Not doing anything
-super: Hi this: Hi
-Redefining calling class
-super: Hi this: SALUTATIONS
-Not doing anything
-super: Hi and then this: SALUTATIONS
diff --git a/test/1996-final-override-virtual-structural/info.txt b/test/1996-final-override-virtual-structural/info.txt
deleted file mode 100644
index 55adf7c..0000000
--- a/test/1996-final-override-virtual-structural/info.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests basic functions in the jvmti plugin.
-
-Tests that using the structural redefinition allows one to override a superclass method.
diff --git a/test/1996-final-override-virtual-structural/run b/test/1996-final-override-virtual-structural/run
deleted file mode 100755
index 03e41a5..0000000
--- a/test/1996-final-override-virtual-structural/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-./default-run "$@" --jvmti --runtime-option -Xopaque-jni-ids:true
diff --git a/test/1996-final-override-virtual-structural/src/Main.java b/test/1996-final-override-virtual-structural/src/Main.java
deleted file mode 100644
index ade69cf..0000000
--- a/test/1996-final-override-virtual-structural/src/Main.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-public class Main {
- public static void main(String[] args) throws Exception {
- art.Test1996.run();
- }
-}
diff --git a/test/1996-final-override-virtual-structural/src/art/Redefinition.java b/test/1996-final-override-virtual-structural/src/art/Redefinition.java
deleted file mode 120000
index 81eaf31..0000000
--- a/test/1996-final-override-virtual-structural/src/art/Redefinition.java
+++ /dev/null
@@ -1 +0,0 @@
-../../../jvmti-common/Redefinition.java
\ No newline at end of file
diff --git a/test/1996-final-override-virtual-structural/src/art/Test1996.java b/test/1996-final-override-virtual-structural/src/art/Test1996.java
deleted file mode 100644
index c2b1125..0000000
--- a/test/1996-final-override-virtual-structural/src/art/Test1996.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.
- */
-
-package art;
-
-import java.util.Base64;
-public class Test1996 {
-
- public static class SuperTransform {
- public String hiValue = "Hi";
- public String sayHi() {
- return this.hiValue;
- }
- }
- public static final class Transform extends SuperTransform {
- public void PostTransform() { }
- public String sayHiTwice(Runnable run) {
- run.run();
- return "super: " + super.sayHi() + " this: " + sayHi();
- }
- }
-
- /**
- * base64 encoded class/dex file for
- * public static final class Transform extends SuperTransform {
- * public String myGreeting;
- * public void PostTransform() {
- * myGreeting = "SALUTATIONS";
- * }
- * public String sayHiTwice(Runnable run) {
- * run.run();
- * return "super: " + super.sayHi() + " and then this: " + sayHi();
- * }
- * public String sayHi() {
- * return myGreeting;
- * }
- * }
- */
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
-"ZGV4CjAzNQAO4Dwurw97RcUtfH7np7S5RR8gsJYOfmeABQAAcAAAAHhWNBIAAAAAAAAAALwEAAAc" +
-"AAAAcAAAAAkAAADgAAAABAAAAAQBAAABAAAANAEAAAoAAAA8AQAAAQAAAIwBAADUAwAArAEAAHYC" +
-"AACIAgAAkAIAAJMCAACXAgAAtgIAANACAADgAgAABAMAACQDAAA6AwAATgMAAGkDAAB4AwAAhQMA" +
-"AJQDAACfAwAAogMAAK8DAAC3AwAAwwMAAMkDAADOAwAA1QMAAOEDAADqAwAA9AMAAPsDAAAEAAAA" +
-"BQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAABAAAAACAAAABgAAAAAAAAADAAAABgAAAGgCAAAD" +
-"AAAABwAAAHACAAAQAAAACAAAAAAAAAABAAYAEwAAAAAAAwABAAAAAAAAABYAAAABAAMAAQAAAAEA" +
-"AwAMAAAAAQAAABYAAAABAAEAFwAAAAUAAwAVAAAABwADAAEAAAAHAAIAEgAAAAcAAAAZAAAAAQAA" +
-"ABEAAAAAAAAAAAAAAA4AAACsBAAAggQAAAAAAAACAAEAAAAAAFsCAAADAAAAVBAAABEAAAAFAAIA" +
-"AgAAAF8CAAAlAAAAchAGAAQAbxABAAMADARuEAQAAwAMACIBBwBwEAcAAQAaAhgAbiAIACEAbiAI" +
-"AEEAGgQAAG4gCABBAG4gCAABAG4QCQABAAwEEQQAAAEAAQABAAAAUgIAAAQAAABwEAAAAAAOAAIA" +
-"AQAAAAAAVgIAAAUAAAAaAA0AWxAAAA4ACgAOAA0ADksAFAAOABABAA48AAAAAAEAAAAFAAAAAQAA" +
-"AAYAECBhbmQgdGhlbiB0aGlzOiAABjxpbml0PgABTAACTEwAHUxhcnQvVGVzdDE5OTYkU3VwZXJU" +
-"cmFuc2Zvcm07ABhMYXJ0L1Rlc3QxOTk2JFRyYW5zZm9ybTsADkxhcnQvVGVzdDE5OTY7ACJMZGFs" +
-"dmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJD" +
-"bGFzczsAFExqYXZhL2xhbmcvUnVubmFibGU7ABJMamF2YS9sYW5nL1N0cmluZzsAGUxqYXZhL2xh" +
-"bmcvU3RyaW5nQnVpbGRlcjsADVBvc3RUcmFuc2Zvcm0AC1NBTFVUQVRJT05TAA1UZXN0MTk5Ni5q" +
-"YXZhAAlUcmFuc2Zvcm0AAVYAC2FjY2Vzc0ZsYWdzAAZhcHBlbmQACm15R3JlZXRpbmcABG5hbWUA" +
-"A3J1bgAFc2F5SGkACnNheUhpVHdpY2UAB3N1cGVyOiAACHRvU3RyaW5nAAV2YWx1ZQB2fn5EOHsi" +
-"Y29tcGlsYXRpb24tbW9kZSI6ImRlYnVnIiwibWluLWFwaSI6MSwic2hhLTEiOiI2MGRhNGQ2N2Iz" +
-"ODFjNDI0Njc3NTdjNDlmYjZlNTU3NTZkODhhMmYzIiwidmVyc2lvbiI6IjEuNy4xMi1kZXYifQAC" +
-"AwEaGAICBAIRBBkUFw8AAQEDAAECgYAEoAQDAbgEAQGsAwEBxAMAAAAAAAACAAAAcwQAAHkEAACg" +
-"BAAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAcAAAAcAAAAAIAAAAJAAAA4AAAAAMA" +
-"AAAEAAAABAEAAAQAAAABAAAANAEAAAUAAAAKAAAAPAEAAAYAAAABAAAAjAEAAAEgAAAEAAAArAEA" +
-"AAMgAAAEAAAAUgIAAAEQAAACAAAAaAIAAAIgAAAcAAAAdgIAAAQgAAACAAAAcwQAAAAgAAABAAAA" +
-"ggQAAAMQAAACAAAAnAQAAAYgAAABAAAArAQAAAAQAAABAAAAvAQAAA==");
-
- public static void run() {
- Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
- doTest(new Transform());
- }
-
- public static void doTest(final Transform t) {
- System.out.println(t.sayHiTwice(() -> { System.out.println("Not doing anything"); }));
- System.out.println(t.sayHiTwice(
- () -> {
- System.out.println("Redefining calling class");
- Redefinition.doCommonStructuralClassRedefinition(Transform.class, DEX_BYTES);
- t.PostTransform();
- }));
- System.out.println(t.sayHiTwice(() -> { System.out.println("Not doing anything"); }));
- }
-}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 069cecb..cd66472 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1146,9 +1146,6 @@
"1991-hello-structural-retransform",
"1992-retransform-no-such-field",
"1993-fallback-non-structural",
- "1994-final-virtual-structural",
- "1995-final-virtual-structural-multithread",
- "1996-final-override-virtual-structural",
"1997-structural-shadow-method",
"1998-structural-shadow-field"
],