diff options
author | 2019-11-18 08:37:50 +0000 | |
---|---|---|
committer | 2019-11-18 08:38:15 +0000 | |
commit | d0e354e54da2f2e79b6fc2ff0e13d53c74976b08 (patch) | |
tree | 743c595ef2cd94f89b487974e698d18c7d297330 | |
parent | c0200a984cacb6c0911d046a018cd11c7d20646b (diff) |
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
36 files changed, 162 insertions, 1358 deletions
diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp index 37ae951720..e7306ba095 100644 --- a/openjdkjvmti/Android.bp +++ b/openjdkjvmti/Android.bp @@ -26,7 +26,6 @@ cc_defaults { 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 4ce376ff9b..665fa9f496 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 @@ namespace openjdkjvmti { // These should never be null. EventHandler* gEventHandler; DeoptManager* gDeoptManager; -AllocationManager* gAllocManager; #define ENSURE_NON_NULL(n) \ do { \ @@ -1499,7 +1497,6 @@ static jint GetEnvHandler(art::JavaVMExt* vm, /*out*/void** env, jint version) { 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 597ab05ba0..0000000000 --- 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 c89d9a633a..0000000000 --- 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 64a02e874c..56406fc81d 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 @@ class JvmtiDdmChunkListener : public art::DdmCallback { 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 @@ class JvmtiEventAllocationListener : public AllocationManager::AllocationCallbac 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 @@ void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) { 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 @@ void EventHandler::Shutdown() { 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 d4eb17137e..c9d587af94 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 @@ class EventHandler { // 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 b25b4d11e2..1d1839014a 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 @@ jvmtiError HeapExtensions::IterateThroughHeapExt(jvmtiEnv* env, 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 @@ static void ReplaceObjectReferences(const ObjectMap& map) 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 @@ static void ReplaceObjectReferences(const ObjectMap& map) } } 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 @@ static void ReplaceObjectReferences(const ObjectMap& map) } 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 ReplaceObjectReferences(const ObjectMap& map) }); } -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 @@ static void ReplaceStrongRoots(art::Thread* self, const ObjectMap& map) 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 @@ static void ReplaceStrongRoots(art::Thread* self, const ObjectMap& map) threads_with_roots_.insert(info.GetThreadId()); } } - *obj = it->second.Ptr(); + *obj = new_val_.Ptr(); } } } @@ -1728,8 +1719,7 @@ static void ReplaceStrongRoots(art::Thread* self, const ObjectMap& map) 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 @@ static void ReplaceStrongRoots(art::Thread* self, const ObjectMap& map) threads_with_roots_.insert(info.GetThreadId()); } } - obj->Assign(it->second); + obj->Assign(new_val_); } } } @@ -1754,10 +1744,11 @@ static void ReplaceStrongRoots(art::Thread* self, const ObjectMap& map) } 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 ReplaceStrongRoots(art::Thread* self, const ObjectMap& map) 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 @@ static void ReplaceWeakRoots(art::Thread* self, // 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 @@ static void ReplaceWeakRoots(art::Thread* self, // 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 @@ static void ReplaceWeakRoots(art::Thread* self, 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 ee8b4d6128..2e27cc7f35 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 @@ class HeapExtensions { 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 ebbe6acdbd..87080caa4e 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 @@ jvmtiError Redefiner::GetClassRedefinitionError(art::Handle<art::mirror::Class> } // 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 @@ bool Redefiner::ClassRedefinition::CheckMethods() { 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 @@ bool Redefiner::ClassRedefinition::CheckFields() { 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 @@ bool Redefiner::ClassRedefinition::CheckRedefinable() { 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 @@ class RedefinitionDataHolder { 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 @@ class RedefinitionDataHolder { 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 @@ class RedefinitionDataHolder { 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 @@ class RedefinitionDataIter { 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 @@ class RedefinitionDataIter { 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 @@ class RedefinitionDataIter { 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 @@ bool Redefiner::ClassRedefinition::AllocateAndRememberNewDexFileCookie( 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 @@ bool Redefiner::EnsureAllClassAllocationsFinished(RedefinitionDataHolder& holder 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 @@ class ScopedDisableConcurrentAndMovingGc { 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 @@ jvmtiError Redefiner::Run() { 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 @@ void Redefiner::ClassRedefinition::CollectNewFieldAndMethodMappings( } } -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 @@ void Redefiner::ClassRedefinition::UpdateClassStructurally(const RedefinitionDat 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); - - // 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()); + 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 + + 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 @@ void Redefiner::ClassRedefinition::UpdateClassStructurally(const RedefinitionDat 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 @@ void Redefiner::ClassRedefinition::UpdateClassStructurally(const RedefinitionDat // 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 cedce92806..58a688c1a0 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 @@ class Redefiner { 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 @@ class Redefiner { 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 @@ class Redefiner { return driver_->IsStructuralRedefinition() && (added_fields_ || added_methods_); } - private: void UpdateClassStructurally(const RedefinitionDataIter& cur_data) REQUIRES(art::Locks::mutator_lock_); @@ -268,7 +257,6 @@ class Redefiner { 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 @@ class Redefiner { 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 c3518f3ccc..4b85df0ea6 100644 --- a/runtime/base/locks.h +++ b/runtime/base/locks.h @@ -129,9 +129,6 @@ enum LockLevel : uint8_t { 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 376b524862..a578252e7a 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 @@ class AllocationListener { 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 04632ef96b..c1b3a63307 100644 --- a/runtime/gc/heap-inl.h +++ b/runtime/gc/heap-inl.h @@ -65,30 +65,10 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, 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 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, // 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 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, 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 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, 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 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, 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 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, } 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 a97ff985e6..85b79da329 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 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, 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 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, 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 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, } 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 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, 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 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, // 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 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, 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 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, } } } -#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 6f6cfd1785..9ef6af5c97 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -1011,10 +1011,8 @@ class Heap { 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 2f36fe6142..6d1a8e0ed6 100644 --- a/runtime/offsets.h +++ b/runtime/offsets.h @@ -37,9 +37,6 @@ class Offset { 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 40a0914278..54e1bcc2fb 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.ArrayList false 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 9b74d30dd9..0000000000 --- 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 606c984f7a..0000000000 --- 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 03e41a58e7..0000000000 --- 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 3f0cb14820..0000000000 --- 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 81eaf31bbb..0000000000 --- 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 9ae7772682..0000000000 --- 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 e69de29bb2..0000000000 --- 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 f9b7bdd04f..0000000000 --- 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 421f7b0bf2..0000000000 --- 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 f19358d626..0000000000 --- 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 81eaf31bbb..0000000000 --- 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 1ffee60a06..0000000000 --- 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 20cd98f1ac..0000000000 --- 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 55adf7c257..0000000000 --- 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 03e41a58e7..0000000000 --- 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 ade69cfe2f..0000000000 --- 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 81eaf31bbb..0000000000 --- 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 c2b1125528..0000000000 --- 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 069cecb27c..cd66472aa8 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" ], |