summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/class_linker.cc70
-rw-r--r--runtime/gc/collector/concurrent_copying.cc21
-rw-r--r--runtime/gc/collector/concurrent_copying.h3
-rw-r--r--runtime/gc/collector/garbage_collector.h5
-rw-r--r--runtime/gc/collector/mark_compact.cc10
-rw-r--r--runtime/gc/collector/mark_compact.h3
-rw-r--r--runtime/gc/collector/mark_sweep.cc9
-rw-r--r--runtime/gc/collector/mark_sweep.h3
-rw-r--r--runtime/gc/collector/semi_space.cc7
-rw-r--r--runtime/gc/collector/semi_space.h3
-rw-r--r--runtime/gc/reference_processor.cc4
-rw-r--r--runtime/gc/reference_queue.cc10
-rw-r--r--runtime/java_vm_ext.cc5
-rw-r--r--runtime/mirror/object_reference-inl.h9
-rw-r--r--runtime/mirror/object_reference.h3
-rw-r--r--runtime/monitor.cc6
-rw-r--r--runtime/native/dalvik_system_VMStack.cc12
-rw-r--r--runtime/openjdkjvmti/Android.bp1
-rw-r--r--runtime/openjdkjvmti/OpenjdkJvmTi.cc9
-rw-r--r--runtime/openjdkjvmti/ti_stack.cc241
-rw-r--r--runtime/openjdkjvmti/ti_stack.h9
-rw-r--r--runtime/openjdkjvmti/ti_thread.cc357
-rw-r--r--runtime/openjdkjvmti/ti_thread.h51
-rw-r--r--runtime/runtime.cc48
-rw-r--r--test/129-ThreadGetId/expected.txt1
-rw-r--r--test/129-ThreadGetId/src/Main.java14
-rw-r--r--test/903-hello-tagging/tagging.cc14
-rw-r--r--test/903-hello-tagging/tagging.h30
-rw-r--r--test/904-object-allocation/tracking.cc15
-rw-r--r--test/904-object-allocation/tracking.h30
-rw-r--r--test/905-object-free/tracking_free.cc14
-rw-r--r--test/905-object-free/tracking_free.h30
-rw-r--r--test/906-iterate-heap/iterate_heap.cc14
-rw-r--r--test/906-iterate-heap/iterate_heap.h30
-rw-r--r--test/907-get-loaded-classes/get_loaded_classes.cc14
-rw-r--r--test/907-get-loaded-classes/get_loaded_classes.h30
-rw-r--r--test/908-gc-start-finish/gc_callbacks.cc14
-rw-r--r--test/908-gc-start-finish/gc_callbacks.h30
-rw-r--r--test/909-attach-agent/expected.txt8
-rwxr-xr-xtest/909-attach-agent/run10
-rw-r--r--test/910-methods/methods.cc14
-rw-r--r--test/910-methods/methods.h30
-rw-r--r--test/911-get-stack-trace/expected.txt737
-rw-r--r--test/911-get-stack-trace/src/Main.java109
-rw-r--r--test/911-get-stack-trace/stack_trace.cc80
-rw-r--r--test/911-get-stack-trace/stack_trace.h30
-rw-r--r--test/912-classes/classes.cc14
-rw-r--r--test/912-classes/classes.h30
-rw-r--r--test/913-heaps/heaps.cc14
-rw-r--r--test/913-heaps/heaps.h30
-rw-r--r--test/918-fields/fields.cc14
-rw-r--r--test/918-fields/fields.h30
-rw-r--r--test/920-objects/objects.cc14
-rw-r--r--test/920-objects/objects.h30
-rw-r--r--test/922-properties/properties.cc14
-rw-r--r--test/922-properties/properties.h30
-rw-r--r--test/923-monitors/monitors.cc14
-rw-r--r--test/923-monitors/monitors.h30
-rwxr-xr-xtest/924-threads/build17
-rw-r--r--test/924-threads/expected.txt30
-rw-r--r--test/924-threads/info.txt1
-rwxr-xr-xtest/924-threads/run19
-rw-r--r--test/924-threads/src/Main.java216
-rw-r--r--test/924-threads/threads.cc104
-rw-r--r--test/Android.bp1
-rw-r--r--test/Android.run-test.mk11
-rw-r--r--test/ti-agent/common_load.cc64
67 files changed, 1991 insertions, 933 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c9b2cc8b68..035ceadeb7 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -6933,7 +6933,7 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() {
method_alignment_);
const size_t old_methods_ptr_size = (old_methods != nullptr) ? old_size : 0;
auto* methods = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(
- class_linker_->GetAllocatorForClassLoader(klass_->GetClassLoader())->Realloc(
+ Runtime::Current()->GetLinearAlloc()->Realloc(
self_, old_methods, old_methods_ptr_size, new_size));
CHECK(methods != nullptr); // Native allocation failure aborts.
@@ -6953,13 +6953,19 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() {
StrideIterator<ArtMethod> out(methods->begin(method_size_, method_alignment_) + old_method_count);
// Copy over miranda methods before copying vtable since CopyOf may cause thread suspension and
// we want the roots of the miranda methods to get visited.
- for (ArtMethod* mir_method : miranda_methods_) {
+ for (size_t i = 0; i < miranda_methods_.size(); ++i) {
+ ArtMethod* mir_method = miranda_methods_[i];
ArtMethod& new_method = *out;
new_method.CopyFrom(mir_method, pointer_size);
new_method.SetAccessFlags(new_method.GetAccessFlags() | kAccMiranda | kAccCopied);
DCHECK_NE(new_method.GetAccessFlags() & kAccAbstract, 0u)
<< "Miranda method should be abstract!";
move_table_.emplace(mir_method, &new_method);
+ // Update the entry in the method array, as the array will be used for future lookups,
+ // where thread suspension is allowed.
+ // As such, the array should not contain locally allocated ArtMethod, otherwise the GC
+ // would not see them.
+ miranda_methods_[i] = &new_method;
++out;
}
// We need to copy the default methods into our own method table since the runtime requires that
@@ -6968,9 +6974,10 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() {
// interface but will have different ArtMethod*s for them. This also means we cannot compare a
// default method found on a class with one found on the declaring interface directly and must
// look at the declaring class to determine if they are the same.
- for (const ScopedArenaVector<ArtMethod*>& methods_vec : {default_methods_,
- overriding_default_methods_}) {
- for (ArtMethod* def_method : methods_vec) {
+ for (ScopedArenaVector<ArtMethod*>* methods_vec : {&default_methods_,
+ &overriding_default_methods_}) {
+ for (size_t i = 0; i < methods_vec->size(); ++i) {
+ ArtMethod* def_method = (*methods_vec)[i];
ArtMethod& new_method = *out;
new_method.CopyFrom(def_method, pointer_size);
// Clear the kAccSkipAccessChecks flag if it is present. Since this class hasn't been
@@ -6981,12 +6988,18 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() {
constexpr uint32_t kMaskFlags = ~kAccSkipAccessChecks;
new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags);
move_table_.emplace(def_method, &new_method);
+ // Update the entry in the method array, as the array will be used for future lookups,
+ // where thread suspension is allowed.
+ // As such, the array should not contain locally allocated ArtMethod, otherwise the GC
+ // would not see them.
+ (*methods_vec)[i] = &new_method;
++out;
}
}
- for (const ScopedArenaVector<ArtMethod*>& methods_vec : {default_conflict_methods_,
- overriding_default_conflict_methods_}) {
- for (ArtMethod* conf_method : methods_vec) {
+ for (ScopedArenaVector<ArtMethod*>* methods_vec : {&default_conflict_methods_,
+ &overriding_default_conflict_methods_}) {
+ for (size_t i = 0; i < methods_vec->size(); ++i) {
+ ArtMethod* conf_method = (*methods_vec)[i];
ArtMethod& new_method = *out;
new_method.CopyFrom(conf_method, pointer_size);
// This is a type of default method (there are default method impls, just a conflict) so
@@ -7002,6 +7015,11 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() {
// that the compiler will not invoke the implementation of whatever method we copied from.
EnsureThrowsInvocationError(class_linker_, &new_method);
move_table_.emplace(conf_method, &new_method);
+ // Update the entry in the method array, as the array will be used for future lookups,
+ // where thread suspension is allowed.
+ // As such, the array should not contain locally allocated ArtMethod, otherwise the GC
+ // would not see them.
+ (*methods_vec)[i] = &new_method;
++out;
}
}
@@ -7034,12 +7052,7 @@ ObjPtr<mirror::PointerArray> ClassLinker::LinkInterfaceMethodsHelper::UpdateVtab
default_conflict_methods_,
miranda_methods_}) {
// These are the functions that are not already in the vtable!
- for (ArtMethod* new_method : methods_vec) {
- auto translated_method_it = move_table_.find(new_method);
- CHECK(translated_method_it != move_table_.end())
- << "We must have a translation for methods added to the classes methods_ array! We "
- << "could not find the ArtMethod added for " << ArtMethod::PrettyMethod(new_method);
- ArtMethod* new_vtable_method = translated_method_it->second;
+ for (ArtMethod* new_vtable_method : methods_vec) {
// Leave the declaring class alone the method's dex_code_item_offset_ and dex_method_index_
// fields are references into the dex file the method was defined in. Since the ArtMethod
// does not store that information it uses declaring_class_->dex_cache_.
@@ -7056,7 +7069,6 @@ ObjPtr<mirror::PointerArray> ClassLinker::LinkInterfaceMethodsHelper::UpdateVtab
ArtMethod* translated_method = vtable->GetElementPtrSize<ArtMethod*>(i, pointer_size);
// Try and find what we need to change this method to.
auto translation_it = default_translations.find(i);
- bool found_translation = false;
if (translation_it != default_translations.end()) {
if (translation_it->second.IsInConflict()) {
// Find which conflict method we are to use for this method.
@@ -7080,30 +7092,28 @@ ObjPtr<mirror::PointerArray> ClassLinker::LinkInterfaceMethodsHelper::UpdateVtab
// Normal default method (changed from an older default or abstract interface method).
DCHECK(translation_it->second.IsTranslation());
translated_method = translation_it->second.GetTranslation();
+ auto it = move_table_.find(translated_method);
+ DCHECK(it != move_table_.end());
+ translated_method = it->second;
}
- found_translation = true;
+ } else {
+ auto it = move_table_.find(translated_method);
+ translated_method = (it != move_table_.end()) ? it->second : nullptr;
}
- DCHECK(translated_method != nullptr);
- auto it = move_table_.find(translated_method);
- if (it != move_table_.end()) {
- auto* new_method = it->second;
- DCHECK(new_method != nullptr);
+
+ if (translated_method != nullptr) {
// Make sure the new_methods index is set.
- if (new_method->GetMethodIndexDuringLinking() != i) {
+ if (translated_method->GetMethodIndexDuringLinking() != i) {
if (kIsDebugBuild) {
auto* methods = klass_->GetMethodsPtr();
CHECK_LE(reinterpret_cast<uintptr_t>(&*methods->begin(method_size_, method_alignment_)),
- reinterpret_cast<uintptr_t>(new_method));
- CHECK_LT(reinterpret_cast<uintptr_t>(new_method),
+ reinterpret_cast<uintptr_t>(translated_method));
+ CHECK_LT(reinterpret_cast<uintptr_t>(translated_method),
reinterpret_cast<uintptr_t>(&*methods->end(method_size_, method_alignment_)));
}
- new_method->SetMethodIndex(0xFFFF & i);
+ translated_method->SetMethodIndex(0xFFFF & i);
}
- vtable->SetElementPtrSize(i, new_method, pointer_size);
- } else {
- // If it was not going to be updated we wouldn't have put it into the default_translations
- // map.
- CHECK(!found_translation) << "We were asked to update this vtable entry. Must not fail.";
+ vtable->SetElementPtrSize(i, translated_method, pointer_size);
}
}
klass_->SetVTable(vtable.Ptr());
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index e1117e6ea3..7b86339663 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -2406,16 +2406,29 @@ void ConcurrentCopying::FinishPhase() {
}
}
-bool ConcurrentCopying::IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* field) {
+bool ConcurrentCopying::IsNullOrMarkedHeapReference(mirror::HeapReference<mirror::Object>* field,
+ bool do_atomic_update) {
mirror::Object* from_ref = field->AsMirrorPtr();
+ if (from_ref == nullptr) {
+ return true;
+ }
mirror::Object* to_ref = IsMarked(from_ref);
if (to_ref == nullptr) {
return false;
}
if (from_ref != to_ref) {
- QuasiAtomic::ThreadFenceRelease();
- field->Assign(to_ref);
- QuasiAtomic::ThreadFenceSequentiallyConsistent();
+ if (do_atomic_update) {
+ do {
+ if (field->AsMirrorPtr() != from_ref) {
+ // Concurrently overwritten by a mutator.
+ break;
+ }
+ } while (!field->CasWeakRelaxed(from_ref, to_ref));
+ } else {
+ QuasiAtomic::ThreadFenceRelease();
+ field->Assign(to_ref);
+ QuasiAtomic::ThreadFenceSequentiallyConsistent();
+ }
}
return true;
}
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index 5b8a557375..844bb450cc 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -183,7 +183,8 @@ class ConcurrentCopying : public GarbageCollector {
REQUIRES_SHARED(Locks::mutator_lock_);
bool IsMarkedInUnevacFromSpace(mirror::Object* from_ref)
REQUIRES_SHARED(Locks::mutator_lock_);
- virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* field) OVERRIDE
+ virtual bool IsNullOrMarkedHeapReference(mirror::HeapReference<mirror::Object>* field,
+ bool do_atomic_update) OVERRIDE
REQUIRES_SHARED(Locks::mutator_lock_);
void SweepSystemWeaks(Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::heap_bitmap_lock_);
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index 5b513991d1..0177e2a1ad 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -187,7 +187,10 @@ class GarbageCollector : public RootVisitor, public IsMarkedVisitor, public Mark
// and will be used for reading system weaks while the GC is running.
virtual mirror::Object* IsMarked(mirror::Object* obj)
REQUIRES_SHARED(Locks::mutator_lock_) = 0;
- virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* obj)
+ // Returns true if the given heap reference is null or is already marked. If it's already marked,
+ // update the reference (uses a CAS if do_atomic_update is true. Otherwise, returns false.
+ virtual bool IsNullOrMarkedHeapReference(mirror::HeapReference<mirror::Object>* obj,
+ bool do_atomic_update)
REQUIRES_SHARED(Locks::mutator_lock_) = 0;
// Used by reference processor.
virtual void ProcessMarkStack() REQUIRES_SHARED(Locks::mutator_lock_) = 0;
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index ddcb6c0698..85e6783599 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -472,9 +472,15 @@ mirror::Object* MarkCompact::IsMarked(mirror::Object* object) {
return mark_bitmap_->Test(object) ? object : nullptr;
}
-bool MarkCompact::IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* ref_ptr) {
+bool MarkCompact::IsNullOrMarkedHeapReference(mirror::HeapReference<mirror::Object>* ref_ptr,
+ // MarkCompact does the GC in a pause. No CAS needed.
+ bool do_atomic_update ATTRIBUTE_UNUSED) {
// Side effect free since we call this before ever moving objects.
- return IsMarked(ref_ptr->AsMirrorPtr()) != nullptr;
+ mirror::Object* obj = ref_ptr->AsMirrorPtr();
+ if (obj == nullptr) {
+ return true;
+ }
+ return IsMarked(obj) != nullptr;
}
void MarkCompact::SweepSystemWeaks() {
diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h
index 564f85b3f8..6d52d5d515 100644
--- a/runtime/gc/collector/mark_compact.h
+++ b/runtime/gc/collector/mark_compact.h
@@ -175,7 +175,8 @@ class MarkCompact : public GarbageCollector {
virtual mirror::Object* IsMarked(mirror::Object* obj) OVERRIDE
REQUIRES_SHARED(Locks::heap_bitmap_lock_)
REQUIRES(Locks::mutator_lock_);
- virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* obj) OVERRIDE
+ virtual bool IsNullOrMarkedHeapReference(mirror::HeapReference<mirror::Object>* obj,
+ bool do_atomic_update) OVERRIDE
REQUIRES_SHARED(Locks::heap_bitmap_lock_)
REQUIRES(Locks::mutator_lock_);
void ForwardObject(mirror::Object* obj) REQUIRES(Locks::heap_bitmap_lock_,
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 06ed0290a9..f00da73458 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -390,8 +390,13 @@ inline void MarkSweep::MarkObjectNonNullParallel(mirror::Object* obj) {
}
}
-bool MarkSweep::IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* ref) {
- return IsMarked(ref->AsMirrorPtr());
+bool MarkSweep::IsNullOrMarkedHeapReference(mirror::HeapReference<mirror::Object>* ref,
+ bool do_atomic_update ATTRIBUTE_UNUSED) {
+ mirror::Object* obj = ref->AsMirrorPtr();
+ if (obj == nullptr) {
+ return true;
+ }
+ return IsMarked(obj);
}
class MarkSweep::MarkObjectSlowPath {
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 02cf462bd3..a6e2d61f6d 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -188,7 +188,8 @@ class MarkSweep : public GarbageCollector {
void VerifyIsLive(const mirror::Object* obj)
REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
- virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* ref) OVERRIDE
+ virtual bool IsNullOrMarkedHeapReference(mirror::HeapReference<mirror::Object>* ref,
+ bool do_atomic_update) OVERRIDE
REQUIRES(Locks::heap_bitmap_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index f2aa5a7599..cb9e7e2c15 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -765,8 +765,13 @@ mirror::Object* SemiSpace::IsMarked(mirror::Object* obj) {
return mark_bitmap_->Test(obj) ? obj : nullptr;
}
-bool SemiSpace::IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* object) {
+bool SemiSpace::IsNullOrMarkedHeapReference(mirror::HeapReference<mirror::Object>* object,
+ // SemiSpace does the GC in a pause. No CAS needed.
+ bool do_atomic_update ATTRIBUTE_UNUSED) {
mirror::Object* obj = object->AsMirrorPtr();
+ if (obj == nullptr) {
+ return true;
+ }
mirror::Object* new_obj = IsMarked(obj);
if (new_obj == nullptr) {
return false;
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 4cebcc3044..52b5e5fe30 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -166,7 +166,8 @@ class SemiSpace : public GarbageCollector {
REQUIRES(Locks::mutator_lock_)
REQUIRES_SHARED(Locks::heap_bitmap_lock_);
- virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* object) OVERRIDE
+ virtual bool IsNullOrMarkedHeapReference(mirror::HeapReference<mirror::Object>* object,
+ bool do_atomic_update) OVERRIDE
REQUIRES(Locks::mutator_lock_)
REQUIRES_SHARED(Locks::heap_bitmap_lock_);
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index 081be968eb..c1548365c7 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -203,7 +203,9 @@ void ReferenceProcessor::DelayReferenceReferent(ObjPtr<mirror::Class> klass,
DCHECK(klass != nullptr);
DCHECK(klass->IsTypeOfReferenceClass());
mirror::HeapReference<mirror::Object>* referent = ref->GetReferentReferenceAddr();
- if (referent->AsMirrorPtr() != nullptr && !collector->IsMarkedHeapReference(referent)) {
+ // do_atomic_update needs to be true because this happens outside of the reference processing
+ // phase.
+ if (!collector->IsNullOrMarkedHeapReference(referent, /*do_atomic_update*/true)) {
Thread* self = Thread::Current();
// TODO: Remove these locks, and use atomic stacks for storing references?
// We need to check that the references haven't already been enqueued since we can end up
diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc
index a0eb197bd5..734caea371 100644
--- a/runtime/gc/reference_queue.cc
+++ b/runtime/gc/reference_queue.cc
@@ -129,8 +129,9 @@ void ReferenceQueue::ClearWhiteReferences(ReferenceQueue* cleared_references,
while (!IsEmpty()) {
ObjPtr<mirror::Reference> ref = DequeuePendingReference();
mirror::HeapReference<mirror::Object>* referent_addr = ref->GetReferentReferenceAddr();
- if (referent_addr->AsMirrorPtr() != nullptr &&
- !collector->IsMarkedHeapReference(referent_addr)) {
+ // do_atomic_update is false because this happens during the reference processing phase where
+ // Reference.clear() would block.
+ if (!collector->IsNullOrMarkedHeapReference(referent_addr, /*do_atomic_update*/false)) {
// Referent is white, clear it.
if (Runtime::Current()->IsActiveTransaction()) {
ref->ClearReferent<true>();
@@ -147,8 +148,9 @@ void ReferenceQueue::EnqueueFinalizerReferences(ReferenceQueue* cleared_referenc
while (!IsEmpty()) {
ObjPtr<mirror::FinalizerReference> ref = DequeuePendingReference()->AsFinalizerReference();
mirror::HeapReference<mirror::Object>* referent_addr = ref->GetReferentReferenceAddr();
- if (referent_addr->AsMirrorPtr() != nullptr &&
- !collector->IsMarkedHeapReference(referent_addr)) {
+ // do_atomic_update is false because this happens during the reference processing phase where
+ // Reference.clear() would block.
+ if (!collector->IsNullOrMarkedHeapReference(referent_addr, /*do_atomic_update*/false)) {
ObjPtr<mirror::Object> forward_address = collector->MarkObject(referent_addr->AsMirrorPtr());
// Move the updated referent to the zombie field.
if (Runtime::Current()->IsActiveTransaction()) {
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index f80c43d80c..e0f28adc4f 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -566,7 +566,10 @@ jweak JavaVMExt::AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) {
return nullptr;
}
MutexLock mu(self, *Locks::jni_weak_globals_lock_);
- while (UNLIKELY(!MayAccessWeakGlobals(self))) {
+ // CMS needs this to block for concurrent reference processing because an object allocated during
+ // the GC won't be marked and concurrent reference processing would incorrectly clear the JNI weak
+ // ref. But CC (kUseReadBarrier == true) doesn't because of the to-space invariant.
+ while (!kUseReadBarrier && UNLIKELY(!MayAccessWeakGlobals(self))) {
// Check and run the empty checkpoint before blocking so the empty checkpoint will work in the
// presence of threads blocking for weak ref access.
self->CheckEmptyCheckpoint();
diff --git a/runtime/mirror/object_reference-inl.h b/runtime/mirror/object_reference-inl.h
index e70b93607e..22fb83cb5c 100644
--- a/runtime/mirror/object_reference-inl.h
+++ b/runtime/mirror/object_reference-inl.h
@@ -34,6 +34,15 @@ HeapReference<MirrorType> HeapReference<MirrorType>::FromObjPtr(ObjPtr<MirrorTyp
return HeapReference<MirrorType>(ptr.Ptr());
}
+template<class MirrorType>
+bool HeapReference<MirrorType>::CasWeakRelaxed(MirrorType* expected_ptr, MirrorType* new_ptr) {
+ HeapReference<Object> expected_ref(HeapReference<Object>::FromMirrorPtr(expected_ptr));
+ HeapReference<Object> new_ref(HeapReference<Object>::FromMirrorPtr(new_ptr));
+ Atomic<uint32_t>* atomic_reference = reinterpret_cast<Atomic<uint32_t>*>(&this->reference_);
+ return atomic_reference->CompareExchangeWeakRelaxed(expected_ref.reference_,
+ new_ref.reference_);
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/object_reference.h b/runtime/mirror/object_reference.h
index 71f34c66e2..a96a120d68 100644
--- a/runtime/mirror/object_reference.h
+++ b/runtime/mirror/object_reference.h
@@ -94,6 +94,9 @@ class MANAGED HeapReference : public ObjectReference<kPoisonHeapReferences, Mirr
static HeapReference<MirrorType> FromObjPtr(ObjPtr<MirrorType> ptr)
REQUIRES_SHARED(Locks::mutator_lock_);
+ bool CasWeakRelaxed(MirrorType* old_ptr, MirrorType* new_ptr)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
explicit HeapReference(MirrorType* mirror_ptr) REQUIRES_SHARED(Locks::mutator_lock_)
: ObjectReference<kPoisonHeapReferences, MirrorType>(mirror_ptr) {}
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 893abd5462..9c0927584e 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -1361,8 +1361,10 @@ void MonitorList::BroadcastForNewMonitors() {
void MonitorList::Add(Monitor* m) {
Thread* self = Thread::Current();
MutexLock mu(self, monitor_list_lock_);
- while (UNLIKELY((!kUseReadBarrier && !allow_new_monitors_) ||
- (kUseReadBarrier && !self->GetWeakRefAccessEnabled()))) {
+ // CMS needs this to block for concurrent reference processing because an object allocated during
+ // the GC won't be marked and concurrent reference processing would incorrectly clear the JNI weak
+ // ref. But CC (kUseReadBarrier == true) doesn't because of the to-space invariant.
+ while (!kUseReadBarrier && UNLIKELY(!allow_new_monitors_)) {
// Check and run the empty checkpoint before blocking so the empty checkpoint will work in the
// presence of threads blocking for weak ref access.
self->CheckEmptyCheckpoint();
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 36825cb870..268d71ac65 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -17,6 +17,7 @@
#include "dalvik_system_VMStack.h"
#include "art_method-inl.h"
+#include "gc/task_processor.h"
#include "jni_internal.h"
#include "nth_caller_visitor.h"
#include "mirror/class-inl.h"
@@ -31,9 +32,18 @@ namespace art {
static jobject GetThreadStack(const ScopedFastNativeObjectAccess& soa, jobject peer)
REQUIRES_SHARED(Locks::mutator_lock_) {
jobject trace = nullptr;
- if (soa.Decode<mirror::Object>(peer) == soa.Self()->GetPeer()) {
+ ObjPtr<mirror::Object> decoded_peer = soa.Decode<mirror::Object>(peer);
+ if (decoded_peer == soa.Self()->GetPeer()) {
trace = soa.Self()->CreateInternalStackTrace<false>(soa);
} else {
+ // Never allow suspending the heap task thread since it may deadlock if allocations are
+ // required for the stack trace.
+ Thread* heap_task_thread =
+ Runtime::Current()->GetHeap()->GetTaskProcessor()->GetRunningThread();
+ // heap_task_thread could be null if the daemons aren't yet started.
+ if (heap_task_thread != nullptr && decoded_peer == heap_task_thread->GetPeer()) {
+ return nullptr;
+ }
// Suspend thread to build stack trace.
ScopedThreadSuspension sts(soa.Self(), kNative);
ThreadList* thread_list = Runtime::Current()->GetThreadList();
diff --git a/runtime/openjdkjvmti/Android.bp b/runtime/openjdkjvmti/Android.bp
index b757b2114f..4bd21b4c2f 100644
--- a/runtime/openjdkjvmti/Android.bp
+++ b/runtime/openjdkjvmti/Android.bp
@@ -29,6 +29,7 @@ cc_defaults {
"ti_properties.cc",
"ti_stack.cc",
"ti_redefine.cc",
+ "ti_thread.cc",
"transform.cc"],
include_dirs: ["art/runtime"],
shared_libs: [
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index c52dd76b59..2629c9fc07 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -55,6 +55,7 @@
#include "ti_properties.h"
#include "ti_redefine.h"
#include "ti_stack.h"
+#include "ti_thread.h"
#include "transform.h"
// TODO Remove this at some point by annotating all the methods. It was put in to make the skeleton
@@ -117,11 +118,11 @@ class JvmtiFunctions {
}
static jvmtiError GetThreadState(jvmtiEnv* env, jthread thread, jint* thread_state_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ThreadUtil::GetThreadState(env, thread, thread_state_ptr);
}
static jvmtiError GetCurrentThread(jvmtiEnv* env, jthread* thread_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ThreadUtil::GetCurrentThread(env, thread_ptr);
}
static jvmtiError GetAllThreads(jvmtiEnv* env, jint* threads_count_ptr, jthread** threads_ptr) {
@@ -159,7 +160,7 @@ class JvmtiFunctions {
}
static jvmtiError GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ThreadUtil::GetThreadInfo(env, thread, info_ptr);
}
static jvmtiError GetOwnedMonitorInfo(jvmtiEnv* env,
@@ -237,7 +238,7 @@ class JvmtiFunctions {
jint max_frame_count,
jvmtiStackInfo** stack_info_ptr,
jint* thread_count_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return StackUtil::GetAllStackTraces(env, max_frame_count, stack_info_ptr, thread_count_ptr);
}
static jvmtiError GetThreadListStackTraces(jvmtiEnv* env,
diff --git a/runtime/openjdkjvmti/ti_stack.cc b/runtime/openjdkjvmti/ti_stack.cc
index 579fb50ecc..098cedbffa 100644
--- a/runtime/openjdkjvmti/ti_stack.cc
+++ b/runtime/openjdkjvmti/ti_stack.cc
@@ -31,9 +31,15 @@
#include "ti_stack.h"
+#include <list>
+#include <unordered_map>
+#include <vector>
+
#include "art_jvmti.h"
#include "art_method-inl.h"
+#include "base/bit_utils.h"
#include "base/enums.h"
+#include "base/mutex.h"
#include "dex_file.h"
#include "dex_file_annotations.h"
#include "jni_env_ext.h"
@@ -41,19 +47,19 @@
#include "mirror/class.h"
#include "mirror/dex_cache.h"
#include "scoped_thread_state_change-inl.h"
+#include "ScopedLocalRef.h"
#include "stack.h"
-#include "thread.h"
+#include "thread-inl.h"
+#include "thread_list.h"
#include "thread_pool.h"
namespace openjdkjvmti {
struct GetStackTraceVisitor : public art::StackVisitor {
GetStackTraceVisitor(art::Thread* thread_in,
- art::ScopedObjectAccessAlreadyRunnable& soa_,
size_t start_,
size_t stop_)
: StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- soa(soa_),
start(start_),
stop(stop_) {}
@@ -85,7 +91,6 @@ struct GetStackTraceVisitor : public art::StackVisitor {
return true;
}
- art::ScopedObjectAccessAlreadyRunnable& soa;
std::vector<jvmtiFrameInfo> frames;
size_t start;
size_t stop;
@@ -99,10 +104,8 @@ struct GetStackTraceClosure : public art::Closure {
start_result(0),
stop_result(0) {}
- void Run(art::Thread* self) OVERRIDE {
- art::ScopedObjectAccess soa(art::Thread::Current());
-
- GetStackTraceVisitor visitor(self, soa, start_input, stop_input);
+ void Run(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ GetStackTraceVisitor visitor(self, start_input, stop_input);
visitor.WalkStack(false);
frames.swap(visitor.frames);
@@ -118,6 +121,44 @@ struct GetStackTraceClosure : public art::Closure {
size_t stop_result;
};
+static jvmtiError TranslateFrameVector(const std::vector<jvmtiFrameInfo>& frames,
+ jint start_depth,
+ size_t start_result,
+ jint max_frame_count,
+ jvmtiFrameInfo* frame_buffer,
+ jint* count_ptr) {
+ size_t collected_frames = frames.size();
+
+ // Assume we're here having collected something.
+ DCHECK_GT(max_frame_count, 0);
+
+ // Frames from the top.
+ if (start_depth >= 0) {
+ if (start_result != 0) {
+ // Not enough frames.
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+ DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
+ if (frames.size() > 0) {
+ memcpy(frame_buffer, frames.data(), collected_frames * sizeof(jvmtiFrameInfo));
+ }
+ *count_ptr = static_cast<jint>(frames.size());
+ return ERR(NONE);
+ }
+
+ // Frames from the bottom.
+ if (collected_frames < static_cast<size_t>(-start_depth)) {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+
+ size_t count = std::min(static_cast<size_t>(-start_depth), static_cast<size_t>(max_frame_count));
+ memcpy(frame_buffer,
+ &frames.data()[collected_frames + start_depth],
+ count * sizeof(jvmtiFrameInfo));
+ *count_ptr = static_cast<jint>(count);
+ return ERR(NONE);
+}
+
jvmtiError StackUtil::GetStackTrace(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
jthread java_thread,
jint start_depth,
@@ -157,35 +198,179 @@ jvmtiError StackUtil::GetStackTrace(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
}
GetStackTraceClosure closure(start_depth >= 0 ? static_cast<size_t>(start_depth) : 0,
- start_depth >= 0 ?static_cast<size_t>(max_frame_count) : 0);
+ start_depth >= 0 ? static_cast<size_t>(max_frame_count) : 0);
thread->RequestSynchronousCheckpoint(&closure);
- size_t collected_frames = closure.frames.size();
+ return TranslateFrameVector(closure.frames,
+ start_depth,
+ closure.start_result,
+ max_frame_count,
+ frame_buffer,
+ count_ptr);
+}
- // Frames from the top.
- if (start_depth >= 0) {
- if (closure.start_result != 0) {
- // Not enough frames.
- return ERR(ILLEGAL_ARGUMENT);
+struct GetAllStackTraceClosure : public art::Closure {
+ public:
+ explicit GetAllStackTraceClosure(size_t stop)
+ : start_input(0),
+ stop_input(stop),
+ frames_lock("GetAllStackTraceGuard", art::LockLevel::kAbortLock),
+ start_result(0),
+ stop_result(0) {}
+
+ void Run(art::Thread* self)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) REQUIRES(!frames_lock) {
+ // self should be live here (so it could be suspended). No need to filter.
+
+ art::Thread* current = art::Thread::Current();
+ std::vector<jvmtiFrameInfo> self_frames;
+
+ GetStackTraceVisitor visitor(self, start_input, stop_input);
+ visitor.WalkStack(false);
+
+ self_frames.swap(visitor.frames);
+
+ art::MutexLock mu(current, frames_lock);
+ frames.emplace(self, self_frames);
+ }
+
+ const size_t start_input;
+ const size_t stop_input;
+
+ art::Mutex frames_lock;
+ std::unordered_map<art::Thread*, std::vector<jvmtiFrameInfo>> frames GUARDED_BY(frames_lock);
+ size_t start_result;
+ size_t stop_result;
+};
+
+
+
+jvmtiError StackUtil::GetAllStackTraces(jvmtiEnv* env,
+ jint max_frame_count,
+ jvmtiStackInfo** stack_info_ptr,
+ jint* thread_count_ptr) {
+ if (max_frame_count < 0) {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+ if (stack_info_ptr == nullptr || thread_count_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+
+ art::Thread* current = art::Thread::Current();
+ art::ScopedObjectAccess soa(current); // Now we know we have the shared lock.
+ art::ScopedThreadSuspension sts(current, art::kWaitingForDebuggerSuspension);
+ art::ScopedSuspendAll ssa("GetAllStackTraces");
+
+ std::vector<art::Thread*> threads;
+ std::vector<std::vector<jvmtiFrameInfo>> frames;
+ {
+ std::list<art::Thread*> thread_list;
+ {
+ art::MutexLock mu(current, *art::Locks::thread_list_lock_);
+ thread_list = art::Runtime::Current()->GetThreadList()->GetList();
}
- DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
- if (closure.frames.size() > 0) {
- memcpy(frame_buffer, closure.frames.data(), collected_frames * sizeof(jvmtiFrameInfo));
+
+ for (art::Thread* thread : thread_list) {
+ // Skip threads that are still starting.
+ if (thread->IsStillStarting()) {
+ continue;
+ }
+
+ GetStackTraceClosure closure(0u, static_cast<size_t>(max_frame_count));
+ thread->RequestSynchronousCheckpoint(&closure);
+
+ threads.push_back(thread);
+ frames.emplace_back();
+ frames.back().swap(closure.frames);
}
- *count_ptr = static_cast<jint>(closure.frames.size());
- return ERR(NONE);
}
- // Frames from the bottom.
- if (collected_frames < static_cast<size_t>(-start_depth)) {
- return ERR(ILLEGAL_ARGUMENT);
+ // Convert the data into our output format. Note: we need to keep the threads suspended,
+ // as we need to access them for their peers.
+
+ // Note: we use an array of jvmtiStackInfo for convenience. The spec says we need to
+ // allocate one big chunk for this and the actual frames, which means we need
+ // to either be conservative or rearrange things later (the latter is implemented).
+ std::unique_ptr<jvmtiStackInfo[]> stack_info_array(new jvmtiStackInfo[frames.size()]);
+ std::vector<std::unique_ptr<jvmtiFrameInfo[]>> frame_infos;
+ frame_infos.reserve(frames.size());
+
+ // Now run through and add data for each thread.
+ size_t sum_frames = 0;
+ for (size_t index = 0; index < frames.size(); ++index) {
+ jvmtiStackInfo& stack_info = stack_info_array.get()[index];
+ memset(&stack_info, 0, sizeof(jvmtiStackInfo));
+
+ art::Thread* self = threads[index];
+ const std::vector<jvmtiFrameInfo>& thread_frames = frames[index];
+
+ // For the time being, set the thread to null. We don't have good ScopedLocalRef
+ // infrastructure.
+ DCHECK(self->GetPeer() != nullptr);
+ stack_info.thread = nullptr;
+ stack_info.state = JVMTI_THREAD_STATE_SUSPENDED;
+
+ size_t collected_frames = thread_frames.size();
+ if (max_frame_count == 0 || collected_frames == 0) {
+ stack_info.frame_count = 0;
+ stack_info.frame_buffer = nullptr;
+ continue;
+ }
+ DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
+
+ jvmtiFrameInfo* frame_info = new jvmtiFrameInfo[collected_frames];
+ frame_infos.emplace_back(frame_info);
+
+ jint count;
+ jvmtiError translate_result = TranslateFrameVector(thread_frames,
+ 0,
+ 0,
+ static_cast<jint>(collected_frames),
+ frame_info,
+ &count);
+ DCHECK(translate_result == JVMTI_ERROR_NONE);
+ stack_info.frame_count = static_cast<jint>(collected_frames);
+ stack_info.frame_buffer = frame_info;
+ sum_frames += static_cast<size_t>(count);
}
- size_t count = std::min(static_cast<size_t>(-start_depth), static_cast<size_t>(max_frame_count));
- memcpy(frame_buffer,
- &closure.frames.data()[collected_frames + start_depth],
- count * sizeof(jvmtiFrameInfo));
- *count_ptr = static_cast<jint>(count);
+ // No errors, yet. Now put it all into an output buffer.
+ size_t rounded_stack_info_size = art::RoundUp(sizeof(jvmtiStackInfo) * frames.size(),
+ alignof(jvmtiFrameInfo));
+ size_t chunk_size = rounded_stack_info_size + sum_frames * sizeof(jvmtiFrameInfo);
+ unsigned char* chunk_data;
+ jvmtiError alloc_result = env->Allocate(chunk_size, &chunk_data);
+ if (alloc_result != ERR(NONE)) {
+ return alloc_result;
+ }
+
+ jvmtiStackInfo* stack_info = reinterpret_cast<jvmtiStackInfo*>(chunk_data);
+ // First copy in all the basic data.
+ memcpy(stack_info, stack_info_array.get(), sizeof(jvmtiStackInfo) * frames.size());
+
+ // Now copy the frames and fix up the pointers.
+ jvmtiFrameInfo* frame_info = reinterpret_cast<jvmtiFrameInfo*>(
+ chunk_data + rounded_stack_info_size);
+ for (size_t i = 0; i < frames.size(); ++i) {
+ jvmtiStackInfo& old_stack_info = stack_info_array.get()[i];
+ jvmtiStackInfo& new_stack_info = stack_info[i];
+
+ jthread thread_peer = current->GetJniEnv()->AddLocalReference<jthread>(threads[i]->GetPeer());
+ new_stack_info.thread = thread_peer;
+
+ if (old_stack_info.frame_count > 0) {
+ // Only copy when there's data - leave the nullptr alone.
+ size_t frames_size = static_cast<size_t>(old_stack_info.frame_count) * sizeof(jvmtiFrameInfo);
+ memcpy(frame_info, old_stack_info.frame_buffer, frames_size);
+ new_stack_info.frame_buffer = frame_info;
+ frame_info += old_stack_info.frame_count;
+ }
+ }
+
+ *stack_info_ptr = stack_info;
+ *thread_count_ptr = static_cast<jint>(frames.size());
+
return ERR(NONE);
}
diff --git a/runtime/openjdkjvmti/ti_stack.h b/runtime/openjdkjvmti/ti_stack.h
index 1931ed3113..7619f98daf 100644
--- a/runtime/openjdkjvmti/ti_stack.h
+++ b/runtime/openjdkjvmti/ti_stack.h
@@ -32,12 +32,21 @@
#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_STACK_H_
#define ART_RUNTIME_OPENJDKJVMTI_TI_STACK_H_
+#include "jni.h"
#include "jvmti.h"
+#include "base/mutex.h"
+
namespace openjdkjvmti {
class StackUtil {
public:
+ static jvmtiError GetAllStackTraces(jvmtiEnv* env,
+ jint max_frame_count,
+ jvmtiStackInfo** stack_info_ptr,
+ jint* thread_count_ptr)
+ REQUIRES(!art::Locks::thread_list_lock_);
+
static jvmtiError GetStackTrace(jvmtiEnv* env,
jthread thread,
jint start_depth,
diff --git a/runtime/openjdkjvmti/ti_thread.cc b/runtime/openjdkjvmti/ti_thread.cc
new file mode 100644
index 0000000000..e20f5605d8
--- /dev/null
+++ b/runtime/openjdkjvmti/ti_thread.cc
@@ -0,0 +1,357 @@
+/* Copyright (C) 2017 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 "ti_thread.h"
+
+#include "art_field.h"
+#include "art_jvmti.h"
+#include "base/logging.h"
+#include "base/mutex.h"
+#include "jni_internal.h"
+#include "mirror/class.h"
+#include "mirror/object-inl.h"
+#include "mirror/string.h"
+#include "obj_ptr.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-inl.h"
+#include "well_known_classes.h"
+
+namespace openjdkjvmti {
+
+jvmtiError ThreadUtil::GetCurrentThread(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread* thread_ptr) {
+ art::Thread* self = art::Thread::Current();
+
+ art::ScopedObjectAccess soa(self);
+
+ jthread thread_peer;
+ if (self->IsStillStarting()) {
+ thread_peer = nullptr;
+ } else {
+ thread_peer = soa.AddLocalReference<jthread>(self->GetPeer());
+ }
+
+ *thread_ptr = thread_peer;
+ return ERR(NONE);
+}
+
+// Read the context classloader from a Java thread object. This is a lazy implementation
+// that assumes GetThreadInfo isn't called too often. If we instead cache the ArtField,
+// we will have to add synchronization as this can't be cached on startup (which is
+// potentially runtime startup).
+static art::ObjPtr<art::mirror::Object> GetContextClassLoader(art::ObjPtr<art::mirror::Object> peer)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (peer == nullptr) {
+ return nullptr;
+ }
+ art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
+ art::ArtField* cc_field = klass->FindDeclaredInstanceField("contextClassLoader",
+ "Ljava/lang/ClassLoader;");
+ CHECK(cc_field != nullptr);
+ return cc_field->GetObject(peer);
+}
+
+// Get the native thread. The spec says a null object denotes the current thread.
+static art::Thread* GetNativeThread(jthread thread,
+ const art::ScopedObjectAccessAlreadyRunnable& soa)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (thread == nullptr) {
+ return art::Thread::Current();
+ }
+
+ art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
+ return art::Thread::FromManagedThread(soa, thread);
+}
+
+jvmtiError ThreadUtil::GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr) {
+ if (info_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ art::ScopedObjectAccess soa(art::Thread::Current());
+
+ art::Thread* self = GetNativeThread(thread, soa);
+ if (self == nullptr && thread == nullptr) {
+ return ERR(INVALID_THREAD);
+ }
+
+ JvmtiUniquePtr name_uptr;
+ if (self != nullptr) {
+ // Have a native thread object, this thread is alive.
+ std::string name;
+ self->GetThreadName(name);
+ jvmtiError name_result = CopyString(
+ env, name.c_str(), reinterpret_cast<unsigned char**>(&info_ptr->name));
+ if (name_result != ERR(NONE)) {
+ return name_result;
+ }
+ name_uptr = MakeJvmtiUniquePtr(env, info_ptr->name);
+
+ info_ptr->priority = self->GetNativePriority();
+
+ info_ptr->is_daemon = self->IsDaemon();
+
+ art::ObjPtr<art::mirror::Object> peer = self->GetPeer();
+
+ // ThreadGroup.
+ if (peer != nullptr) {
+ art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group);
+ CHECK(f != nullptr);
+ art::ObjPtr<art::mirror::Object> group = f->GetObject(peer);
+ info_ptr->thread_group = group == nullptr
+ ? nullptr
+ : soa.AddLocalReference<jthreadGroup>(group);
+ } else {
+ info_ptr->thread_group = nullptr;
+ }
+
+ // Context classloader.
+ art::ObjPtr<art::mirror::Object> ccl = GetContextClassLoader(peer);
+ info_ptr->context_class_loader = ccl == nullptr
+ ? nullptr
+ : soa.AddLocalReference<jobject>(ccl);
+ } else {
+ // Only the peer. This thread has either not been started, or is dead. Read things from
+ // the Java side.
+ art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread);
+
+ // Name.
+ {
+ art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_name);
+ CHECK(f != nullptr);
+ art::ObjPtr<art::mirror::Object> name = f->GetObject(peer);
+ std::string name_cpp;
+ const char* name_cstr;
+ if (name != nullptr) {
+ name_cpp = name->AsString()->ToModifiedUtf8();
+ name_cstr = name_cpp.c_str();
+ } else {
+ name_cstr = "";
+ }
+ jvmtiError name_result = CopyString(
+ env, name_cstr, reinterpret_cast<unsigned char**>(&info_ptr->name));
+ if (name_result != ERR(NONE)) {
+ return name_result;
+ }
+ name_uptr = MakeJvmtiUniquePtr(env, info_ptr->name);
+ }
+
+ // Priority.
+ {
+ art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_priority);
+ CHECK(f != nullptr);
+ info_ptr->priority = static_cast<jint>(f->GetInt(peer));
+ }
+
+ // Daemon.
+ {
+ art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_daemon);
+ CHECK(f != nullptr);
+ info_ptr->is_daemon = f->GetBoolean(peer) == 0 ? JNI_FALSE : JNI_TRUE;
+ }
+
+ // ThreadGroup.
+ {
+ art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group);
+ CHECK(f != nullptr);
+ art::ObjPtr<art::mirror::Object> group = f->GetObject(peer);
+ info_ptr->thread_group = group == nullptr
+ ? nullptr
+ : soa.AddLocalReference<jthreadGroup>(group);
+ }
+
+ // Context classloader.
+ art::ObjPtr<art::mirror::Object> ccl = GetContextClassLoader(peer);
+ info_ptr->context_class_loader = ccl == nullptr
+ ? nullptr
+ : soa.AddLocalReference<jobject>(ccl);
+ }
+
+ name_uptr.release();
+
+ return ERR(NONE);
+}
+
+// Return the thread's (or current thread, if null) thread state. Return kStarting in case
+// there's no native counterpart (thread hasn't been started, yet, or is dead).
+static art::ThreadState GetNativeThreadState(jthread thread,
+ const art::ScopedObjectAccessAlreadyRunnable& soa,
+ art::Thread** native_thread)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ art::Thread* self = nullptr;
+ art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
+ if (thread == nullptr) {
+ self = art::Thread::Current();
+ } else {
+ self = art::Thread::FromManagedThread(soa, thread);
+ }
+ *native_thread = self;
+ if (self == nullptr || self->IsStillStarting()) {
+ return art::ThreadState::kStarting;
+ }
+ return self->GetState();
+}
+
+static jint GetJvmtiThreadStateFromInternal(art::ThreadState internal_thread_state) {
+ jint jvmti_state = JVMTI_THREAD_STATE_ALIVE;
+
+ if (internal_thread_state == art::ThreadState::kSuspended) {
+ jvmti_state |= JVMTI_THREAD_STATE_SUSPENDED;
+ // Note: We do not have data about the previous state. Otherwise we should load the previous
+ // state here.
+ }
+
+ if (internal_thread_state == art::ThreadState::kNative) {
+ jvmti_state |= JVMTI_THREAD_STATE_IN_NATIVE;
+ }
+
+ if (internal_thread_state == art::ThreadState::kRunnable ||
+ internal_thread_state == art::ThreadState::kWaitingWeakGcRootRead ||
+ internal_thread_state == art::ThreadState::kSuspended) {
+ jvmti_state |= JVMTI_THREAD_STATE_RUNNABLE;
+ } else if (internal_thread_state == art::ThreadState::kBlocked) {
+ jvmti_state |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
+ } else {
+ // Should be in waiting state.
+ jvmti_state |= JVMTI_THREAD_STATE_WAITING;
+
+ if (internal_thread_state == art::ThreadState::kTimedWaiting ||
+ internal_thread_state == art::ThreadState::kSleeping) {
+ jvmti_state |= JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT;
+ } else {
+ jvmti_state |= JVMTI_THREAD_STATE_WAITING_INDEFINITELY;
+ }
+
+ if (internal_thread_state == art::ThreadState::kSleeping) {
+ jvmti_state |= JVMTI_THREAD_STATE_SLEEPING;
+ }
+
+ if (internal_thread_state == art::ThreadState::kTimedWaiting ||
+ internal_thread_state == art::ThreadState::kWaiting) {
+ jvmti_state |= JVMTI_THREAD_STATE_IN_OBJECT_WAIT;
+ }
+
+ // TODO: PARKED. We'll have to inspect the stack.
+ }
+
+ return jvmti_state;
+}
+
+static jint GetJavaStateFromInternal(art::ThreadState internal_thread_state) {
+ switch (internal_thread_state) {
+ case art::ThreadState::kTerminated:
+ return JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
+
+ case art::ThreadState::kRunnable:
+ case art::ThreadState::kNative:
+ case art::ThreadState::kWaitingWeakGcRootRead:
+ case art::ThreadState::kSuspended:
+ return JVMTI_JAVA_LANG_THREAD_STATE_RUNNABLE;
+
+ case art::ThreadState::kTimedWaiting:
+ case art::ThreadState::kSleeping:
+ return JVMTI_JAVA_LANG_THREAD_STATE_TIMED_WAITING;
+
+ case art::ThreadState::kBlocked:
+ return JVMTI_JAVA_LANG_THREAD_STATE_BLOCKED;
+
+ case art::ThreadState::kStarting:
+ return JVMTI_JAVA_LANG_THREAD_STATE_NEW;
+
+ case art::ThreadState::kWaiting:
+ case art::ThreadState::kWaitingForGcToComplete:
+ case art::ThreadState::kWaitingPerformingGc:
+ case art::ThreadState::kWaitingForCheckPointsToRun:
+ case art::ThreadState::kWaitingForDebuggerSend:
+ case art::ThreadState::kWaitingForDebuggerToAttach:
+ case art::ThreadState::kWaitingInMainDebuggerLoop:
+ case art::ThreadState::kWaitingForDebuggerSuspension:
+ case art::ThreadState::kWaitingForDeoptimization:
+ case art::ThreadState::kWaitingForGetObjectsAllocated:
+ case art::ThreadState::kWaitingForJniOnLoad:
+ case art::ThreadState::kWaitingForSignalCatcherOutput:
+ case art::ThreadState::kWaitingInMainSignalCatcherLoop:
+ case art::ThreadState::kWaitingForMethodTracingStart:
+ case art::ThreadState::kWaitingForVisitObjects:
+ case art::ThreadState::kWaitingForGcThreadFlip:
+ return JVMTI_JAVA_LANG_THREAD_STATE_WAITING;
+ }
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+}
+
+jvmtiError ThreadUtil::GetThreadState(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jthread thread,
+ jint* thread_state_ptr) {
+ if (thread_state_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ art::Thread* native_thread = nullptr;
+ art::ThreadState internal_thread_state = GetNativeThreadState(thread, soa, &native_thread);
+
+ if (internal_thread_state == art::ThreadState::kStarting) {
+ if (thread == nullptr) {
+ // No native thread, and no Java thread? We must be starting up. Report as wrong phase.
+ return ERR(WRONG_PHASE);
+ }
+
+ // Need to read the Java "started" field to know whether this is starting or terminated.
+ art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread);
+ art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
+ art::ArtField* started_field = klass->FindDeclaredInstanceField("started", "Z");
+ CHECK(started_field != nullptr);
+ bool started = started_field->GetBoolean(peer) != 0;
+ constexpr jint kStartedState = JVMTI_JAVA_LANG_THREAD_STATE_NEW;
+ constexpr jint kTerminatedState = JVMTI_THREAD_STATE_TERMINATED |
+ JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
+ *thread_state_ptr = started ? kTerminatedState : kStartedState;
+ return ERR(NONE);
+ }
+ DCHECK(native_thread != nullptr);
+
+ // Translate internal thread state to JVMTI and Java state.
+ jint jvmti_state = GetJvmtiThreadStateFromInternal(internal_thread_state);
+ if (native_thread->IsInterrupted()) {
+ jvmti_state |= JVMTI_THREAD_STATE_INTERRUPTED;
+ }
+
+ // Java state is derived from nativeGetState.
+ // Note: Our implementation assigns "runnable" to suspended. As such, we will have slightly
+ // different mask. However, this is for consistency with the Java view.
+ jint java_state = GetJavaStateFromInternal(internal_thread_state);
+
+ *thread_state_ptr = jvmti_state | java_state;
+
+ return ERR(NONE);
+}
+
+} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_thread.h b/runtime/openjdkjvmti/ti_thread.h
new file mode 100644
index 0000000000..b6ffbb5f65
--- /dev/null
+++ b/runtime/openjdkjvmti/ti_thread.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2017 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_RUNTIME_OPENJDKJVMTI_TI_THREAD_H_
+#define ART_RUNTIME_OPENJDKJVMTI_TI_THREAD_H_
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace openjdkjvmti {
+
+class ThreadUtil {
+ public:
+ static jvmtiError GetCurrentThread(jvmtiEnv* env, jthread* thread_ptr);
+
+ static jvmtiError GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr);
+
+ static jvmtiError GetThreadState(jvmtiEnv* env, jthread thread, jint* thread_state_ptr);
+};
+
+} // namespace openjdkjvmti
+
+#endif // ART_RUNTIME_OPENJDKJVMTI_TI_THREAD_H_
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 2086d70791..df5fc5ce8a 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1364,6 +1364,39 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
return true;
}
+static bool EnsureJvmtiPlugin(Runtime* runtime,
+ std::vector<Plugin>* plugins,
+ std::string* error_msg) {
+ constexpr const char* plugin_name = kIsDebugBuild ? "libopenjdkjvmtid.so" : "libopenjdkjvmti.so";
+
+ // Is the plugin already loaded?
+ for (Plugin p : *plugins) {
+ if (p.GetLibrary() == plugin_name) {
+ return true;
+ }
+ }
+
+ // Is the process debuggable? Otherwise, do not attempt to load the plugin.
+ if (!runtime->IsDebuggable()) {
+ *error_msg = "Process is not debuggable.";
+ return false;
+ }
+
+ Plugin new_plugin = Plugin::Create(plugin_name);
+
+ // Suspend all threads to protect ourself somewhat.
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self); // Now we know we have the shared lock.
+ ScopedThreadSuspension sts(self, art::kWaitingForDebuggerToAttach);
+ ScopedSuspendAll ssa("EnsureJvmtiPlugin");
+ if (!new_plugin.Load(error_msg)) {
+ return false;
+ }
+
+ plugins->push_back(std::move(new_plugin));
+ return true;
+}
+
// Attach a new agent and add it to the list of runtime agents
//
// TODO: once we decide on the threading model for agents,
@@ -1371,18 +1404,25 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
// (and we synchronize access to any shared data structures like "agents_")
//
void Runtime::AttachAgent(const std::string& agent_arg) {
+ std::string error_msg;
+ if (!EnsureJvmtiPlugin(this, &plugins_, &error_msg)) {
+ LOG(WARNING) << "Could not load plugin: " << error_msg;
+ ScopedObjectAccess soa(Thread::Current());
+ ThrowIOException("%s", error_msg.c_str());
+ return;
+ }
+
ti::Agent agent(agent_arg);
int res = 0;
- std::string err;
- ti::Agent::LoadError result = agent.Attach(&res, &err);
+ ti::Agent::LoadError result = agent.Attach(&res, &error_msg);
if (result == ti::Agent::kNoError) {
agents_.push_back(std::move(agent));
} else {
- LOG(ERROR) << "Agent attach failed (result=" << result << ") : " << err;
+ LOG(WARNING) << "Agent attach failed (result=" << result << ") : " << error_msg;
ScopedObjectAccess soa(Thread::Current());
- ThrowWrappedIOException("%s", err.c_str());
+ ThrowIOException("%s", error_msg.c_str());
}
}
diff --git a/test/129-ThreadGetId/expected.txt b/test/129-ThreadGetId/expected.txt
index 134d8d0b47..aadf90d9d7 100644
--- a/test/129-ThreadGetId/expected.txt
+++ b/test/129-ThreadGetId/expected.txt
@@ -1 +1,2 @@
+HeapTaskDaemon depth 0
Finishing
diff --git a/test/129-ThreadGetId/src/Main.java b/test/129-ThreadGetId/src/Main.java
index 9934bba95f..5aefd17f0e 100644
--- a/test/129-ThreadGetId/src/Main.java
+++ b/test/129-ThreadGetId/src/Main.java
@@ -22,6 +22,7 @@ public class Main implements Runnable {
public static void main(String[] args) throws Exception {
final Thread[] threads = new Thread[numberOfThreads];
+ test_getStackTraces();
for (int t = 0; t < threads.length; t++) {
threads[t] = new Thread(new Main());
threads[t].start();
@@ -32,6 +33,19 @@ public class Main implements Runnable {
System.out.println("Finishing");
}
+ static void test_getStackTraces() {
+ // Check all the current threads for positive IDs.
+ Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
+ for (Map.Entry<Thread, StackTraceElement[]> pair : map.entrySet()) {
+ Thread thread = pair.getKey();
+ // Expect empty stack trace since we do not support suspending the GC thread for
+ // obtaining stack traces. See b/28261069.
+ if (thread.getName().equals("HeapTaskDaemon")) {
+ System.out.println(thread.getName() + " depth " + pair.getValue().length);
+ }
+ }
+ }
+
public void test_getId() {
if (Thread.currentThread().getId() <= 0) {
System.out.println("current thread's ID is not positive");
diff --git a/test/903-hello-tagging/tagging.cc b/test/903-hello-tagging/tagging.cc
index 60a31bdd2d..f74c1fc2ea 100644
--- a/test/903-hello-tagging/tagging.cc
+++ b/test/903-hello-tagging/tagging.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "tagging.h"
-
#include <iostream>
#include <pthread.h>
#include <stdio.h>
@@ -141,18 +139,6 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getTaggedObjects(JNIEnv* env
return resultArray;
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test903HelloTagging
} // namespace art
diff --git a/test/903-hello-tagging/tagging.h b/test/903-hello-tagging/tagging.h
deleted file mode 100644
index f062d44880..0000000000
--- a/test/903-hello-tagging/tagging.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_903_HELLO_TAGGING_TAGGING_H_
-#define ART_TEST_903_HELLO_TAGGING_TAGGING_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test903HelloTagging {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test903HelloTagging
-} // namespace art
-
-#endif // ART_TEST_903_HELLO_TAGGING_TAGGING_H_
diff --git a/test/904-object-allocation/tracking.cc b/test/904-object-allocation/tracking.cc
index f993606b42..95eab0c6cc 100644
--- a/test/904-object-allocation/tracking.cc
+++ b/test/904-object-allocation/tracking.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "tracking.h"
-
#include <iostream>
#include <pthread.h>
#include <stdio.h>
@@ -89,19 +87,6 @@ extern "C" JNIEXPORT void JNICALL Java_Main_enableAllocationTracking(JNIEnv* env
}
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, nullptr);
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test904ObjectAllocation
} // namespace art
diff --git a/test/904-object-allocation/tracking.h b/test/904-object-allocation/tracking.h
deleted file mode 100644
index 21c1837523..0000000000
--- a/test/904-object-allocation/tracking.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_904_OBJECT_ALLOCATION_TRACKING_H_
-#define ART_TEST_904_OBJECT_ALLOCATION_TRACKING_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test904ObjectAllocation {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test904ObjectAllocation
-} // namespace art
-
-#endif // ART_TEST_904_OBJECT_ALLOCATION_TRACKING_H_
diff --git a/test/905-object-free/tracking_free.cc b/test/905-object-free/tracking_free.cc
index 7f295accb2..7b26d79edb 100644
--- a/test/905-object-free/tracking_free.cc
+++ b/test/905-object-free/tracking_free.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "tracking_free.h"
-
#include <iostream>
#include <pthread.h>
#include <stdio.h>
@@ -82,17 +80,5 @@ extern "C" JNIEXPORT jlongArray JNICALL Java_Main_getCollectedTags(JNIEnv* env,
return ret;
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test905ObjectFree
} // namespace art
diff --git a/test/905-object-free/tracking_free.h b/test/905-object-free/tracking_free.h
deleted file mode 100644
index ba4aa43ffe..0000000000
--- a/test/905-object-free/tracking_free.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_905_OBJECT_FREE_TRACKING_FREE_H_
-#define ART_TEST_905_OBJECT_FREE_TRACKING_FREE_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test905ObjectFree {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test905ObjectFree
-} // namespace art
-
-#endif // ART_TEST_905_OBJECT_FREE_TRACKING_FREE_H_
diff --git a/test/906-iterate-heap/iterate_heap.cc b/test/906-iterate-heap/iterate_heap.cc
index a2fd59128f..1362d470e6 100644
--- a/test/906-iterate-heap/iterate_heap.cc
+++ b/test/906-iterate-heap/iterate_heap.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "iterate_heap.h"
-
#include <iostream>
#include <pthread.h>
#include <stdio.h>
@@ -174,17 +172,5 @@ extern "C" JNIEXPORT void JNICALL Java_Main_iterateThroughHeapAdd(JNIEnv* env AT
Run(heap_filter, klass_filter, &config);
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test906IterateHeap
} // namespace art
diff --git a/test/906-iterate-heap/iterate_heap.h b/test/906-iterate-heap/iterate_heap.h
deleted file mode 100644
index f25cdbaf49..0000000000
--- a/test/906-iterate-heap/iterate_heap.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_906_ITERATE_HEAP_ITERATE_HEAP_H_
-#define ART_TEST_906_ITERATE_HEAP_ITERATE_HEAP_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test906IterateHeap {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test906IterateHeap
-} // namespace art
-
-#endif // ART_TEST_906_ITERATE_HEAP_ITERATE_HEAP_H_
diff --git a/test/907-get-loaded-classes/get_loaded_classes.cc b/test/907-get-loaded-classes/get_loaded_classes.cc
index 36d33b63cc..5bda7ebac8 100644
--- a/test/907-get-loaded-classes/get_loaded_classes.cc
+++ b/test/907-get-loaded-classes/get_loaded_classes.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "get_loaded_classes.h"
-
#include <iostream>
#include <pthread.h>
#include <stdio.h>
@@ -65,17 +63,5 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getLoadedClasses(
return ret;
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test907GetLoadedClasses
} // namespace art
diff --git a/test/907-get-loaded-classes/get_loaded_classes.h b/test/907-get-loaded-classes/get_loaded_classes.h
deleted file mode 100644
index 4d27f898cc..0000000000
--- a/test/907-get-loaded-classes/get_loaded_classes.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_907_GET_LOADED_CLASSES_GET_LOADED_CLASSES_H_
-#define ART_TEST_907_GET_LOADED_CLASSES_GET_LOADED_CLASSES_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test907GetLoadedClasses {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test907GetLoadedClasses
-} // namespace art
-
-#endif // ART_TEST_907_GET_LOADED_CLASSES_GET_LOADED_CLASSES_H_
diff --git a/test/908-gc-start-finish/gc_callbacks.cc b/test/908-gc-start-finish/gc_callbacks.cc
index 1fab79dcb1..59801ff648 100644
--- a/test/908-gc-start-finish/gc_callbacks.cc
+++ b/test/908-gc-start-finish/gc_callbacks.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "gc_callbacks.h"
-
#include <stdio.h>
#include <string.h>
@@ -94,17 +92,5 @@ extern "C" JNIEXPORT jint JNICALL Java_Main_getGcFinishes(JNIEnv* env ATTRIBUTE_
return result;
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test908GcStartFinish
} // namespace art
diff --git a/test/908-gc-start-finish/gc_callbacks.h b/test/908-gc-start-finish/gc_callbacks.h
deleted file mode 100644
index 177a4eb7b2..0000000000
--- a/test/908-gc-start-finish/gc_callbacks.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_908_GC_START_FINISH_GC_CALLBACKS_H_
-#define ART_TEST_908_GC_START_FINISH_GC_CALLBACKS_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test908GcStartFinish {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test908GcStartFinish
-} // namespace art
-
-#endif // ART_TEST_908_GC_START_FINISH_GC_CALLBACKS_H_
diff --git a/test/909-attach-agent/expected.txt b/test/909-attach-agent/expected.txt
index eacc595aaf..c0bccd6486 100644
--- a/test/909-attach-agent/expected.txt
+++ b/test/909-attach-agent/expected.txt
@@ -1,3 +1,11 @@
Hello, world!
Attached Agent for test 909-attach-agent
Goodbye!
+Hello, world!
+Attached Agent for test 909-attach-agent
+Goodbye!
+Hello, world!
+java.io.IOException: Process is not debuggable.
+ at dalvik.system.VMDebug.attachAgent(Native Method)
+ at Main.main(Main.java:27)
+Goodbye!
diff --git a/test/909-attach-agent/run b/test/909-attach-agent/run
index aed6e83d67..985341bd4f 100755
--- a/test/909-attach-agent/run
+++ b/test/909-attach-agent/run
@@ -24,4 +24,14 @@ fi
./default-run "$@" --experimental agents \
--experimental runtime-plugins \
--android-runtime-option -Xplugin:${plugin} \
+ --android-runtime-option -Xfully-deoptable \
+ --args agent:${agent}=909-attach-agent
+
+./default-run "$@" --experimental agents \
+ --experimental runtime-plugins \
+ --android-runtime-option -Xfully-deoptable \
+ --args agent:${agent}=909-attach-agent
+
+./default-run "$@" --experimental agents \
+ --experimental runtime-plugins \
--args agent:${agent}=909-attach-agent
diff --git a/test/910-methods/methods.cc b/test/910-methods/methods.cc
index fa9679db4b..f60fabb1df 100644
--- a/test/910-methods/methods.cc
+++ b/test/910-methods/methods.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "methods.h"
-
#include <stdio.h>
#include "base/macros.h"
@@ -207,17 +205,5 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isMethodSynthetic(
return is_synthetic;
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test910Methods
} // namespace art
diff --git a/test/910-methods/methods.h b/test/910-methods/methods.h
deleted file mode 100644
index 93d18741ed..0000000000
--- a/test/910-methods/methods.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_910_METHODS_METHODS_H_
-#define ART_TEST_910_METHODS_METHODS_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test910Methods {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test910Methods
-} // namespace art
-
-#endif // ART_TEST_910_METHODS_METHODS_H_
diff --git a/test/911-get-stack-trace/expected.txt b/test/911-get-stack-trace/expected.txt
index f8c97ce475..e40698acc5 100644
--- a/test/911-get-stack-trace/expected.txt
+++ b/test/911-get-stack-trace/expected.txt
@@ -4,72 +4,72 @@
From top
---------
getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2
- print (Ljava/lang/Thread;II)V 0 124
- printOrWait (IILMain$ControlData;)V 6 151
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- doTest ()V 38 34
- main ([Ljava/lang/String;)V 6 24
----------
- print (Ljava/lang/Thread;II)V 0 124
- printOrWait (IILMain$ControlData;)V 6 151
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- doTest ()V 42 35
- main ([Ljava/lang/String;)V 6 24
+ print (Ljava/lang/Thread;II)V 0 183
+ printOrWait (IILMain$ControlData;)V 6 246
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ doTest ()V 38 41
+ main ([Ljava/lang/String;)V 6 27
+---------
+ print (Ljava/lang/Thread;II)V 0 183
+ printOrWait (IILMain$ControlData;)V 6 246
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ doTest ()V 42 42
+ main ([Ljava/lang/String;)V 6 27
---------
getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2
- print (Ljava/lang/Thread;II)V 0 124
- printOrWait (IILMain$ControlData;)V 6 151
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
----------
- printOrWait (IILMain$ControlData;)V 6 151
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
+ print (Ljava/lang/Thread;II)V 0 183
+ printOrWait (IILMain$ControlData;)V 6 246
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+---------
+ printOrWait (IILMain$ControlData;)V 6 246
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
From bottom
---------
- main ([Ljava/lang/String;)V 6 24
+ main ([Ljava/lang/String;)V 6 27
---------
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- doTest ()V 65 41
- main ([Ljava/lang/String;)V 6 24
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ doTest ()V 65 48
+ main ([Ljava/lang/String;)V 6 27
---------
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
################################
### Other thread (suspended) ###
@@ -77,132 +77,519 @@ From bottom
From top
---------
wait ()V -1 -2
- printOrWait (IILMain$ControlData;)V 24 157
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 54
----------
- printOrWait (IILMain$ControlData;)V 24 157
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 54
----------
- wait ()V -1 -2
- printOrWait (IILMain$ControlData;)V 24 157
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
----------
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 61
+---------
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 61
+---------
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+---------
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
From bottom
---------
- run ()V 4 54
+ run ()V 4 61
---------
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 54
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 61
---------
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
###########################
### Other thread (live) ###
###########################
From top
---------
- printOrWait (IILMain$ControlData;)V 44 164
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 88
----------
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 88
----------
- printOrWait (IILMain$ControlData;)V 44 164
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
----------
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
+ printOrWait (IILMain$ControlData;)V 44 259
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 95
+---------
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 95
+---------
+ printOrWait (IILMain$ControlData;)V 44 259
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+---------
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
From bottom
---------
- run ()V 4 88
+ run ()V 4 95
+---------
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 95
+---------
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+
+################################
+### Other threads (suspended) ###
+################################
+---------
+FinalizerDaemon
+<not printed>
+---------
+FinalizerWatchdogDaemon
+<not printed>
+---------
+HeapTaskDaemon
+<not printed>
+---------
+ReferenceQueueDaemon
+<not printed>
+---------
+Signal Catcher
+
+---------
+Thread-10
+
+---------
+Thread-11
+
+---------
+Thread-12
+
+---------
+Thread-13
+
+---------
+Thread-4
+
+---------
+Thread-5
+
+---------
+Thread-6
+
+---------
+Thread-7
+
+---------
+Thread-8
+
+---------
+Thread-9
+
+---------
+main
+
+---------
+FinalizerDaemon
+<not printed>
+---------
+FinalizerWatchdogDaemon
+<not printed>
+---------
+HeapTaskDaemon
+<not printed>
+---------
+ReferenceQueueDaemon
+<not printed>
+---------
+Signal Catcher
+
+---------
+Thread-10
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+
+---------
+Thread-11
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+
+---------
+Thread-12
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+
+---------
+Thread-13
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+
+---------
+Thread-4
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+
+---------
+Thread-5
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+
+---------
+Thread-6
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+
+---------
+Thread-7
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+
+---------
+Thread-8
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+
+---------
+Thread-9
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+
+---------
+main
+ getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
+ printAll (I)V 0 219
+ doTestAllStackTraces ()V 107 156
+ main ([Ljava/lang/String;)V 15 31
+
+---------
+FinalizerDaemon
+<not printed>
+---------
+FinalizerWatchdogDaemon
+<not printed>
+---------
+HeapTaskDaemon
+<not printed>
+---------
+ReferenceQueueDaemon
+<not printed>
+---------
+Signal Catcher
+
+---------
+Thread-10
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 144
+
+---------
+Thread-11
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 144
+
---------
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 88
+Thread-12
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 144
+
---------
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
+Thread-13
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 144
+
+---------
+Thread-4
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 144
+
+---------
+Thread-5
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 144
+
+---------
+Thread-6
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 144
+
+---------
+Thread-7
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 144
+
+---------
+Thread-8
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 144
+
+---------
+Thread-9
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 252
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 237
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 239
+ bar (IIILMain$ControlData;)J 0 231
+ foo (IIILMain$ControlData;)I 0 226
+ run ()V 4 144
+
+---------
+main
+ getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
+ printAll (I)V 0 219
+ doTestAllStackTraces ()V 112 158
+ main ([Ljava/lang/String;)V 15 31
+
+Done
diff --git a/test/911-get-stack-trace/src/Main.java b/test/911-get-stack-trace/src/Main.java
index 722bee8056..3479abbeae 100644
--- a/test/911-get-stack-trace/src/Main.java
+++ b/test/911-get-stack-trace/src/Main.java
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
public class Main {
@@ -24,6 +27,10 @@ public class Main {
doTest();
doTestOtherThreadWait();
doTestOtherThreadBusyLoop();
+
+ doTestAllStackTraces();
+
+ System.out.println("Done");
}
public static void doTest() throws Exception {
@@ -109,6 +116,58 @@ public class Main {
t.join();
}
+ private final static List<Object> RETAIN = new ArrayList<Object>();
+
+ public static void doTestAllStackTraces() throws Exception {
+ System.out.println();
+ System.out.println("################################");
+ System.out.println("### Other threads (suspended) ###");
+ System.out.println("################################");
+
+ // Also create an unstarted and a dead thread.
+ RETAIN.add(new Thread());
+ Thread deadThread = new Thread();
+ RETAIN.add(deadThread);
+ deadThread.start();
+ deadThread.join();
+
+ final int N = 10;
+
+ final ControlData data = new ControlData(N);
+ data.waitFor = new Object();
+
+ Thread threads[] = new Thread[N];
+
+ for (int i = 0; i < N; i++) {
+ Thread t = new Thread() {
+ public void run() {
+ Recurse.foo(4, 0, 0, data);
+ }
+ };
+ t.start();
+ threads[i] = t;
+ }
+ data.reached.await();
+ Thread.yield();
+ Thread.sleep(500); // A little bit of time...
+
+ printAll(0);
+
+ printAll(5);
+
+ printAll(25);
+
+ // Let the thread make progress and die.
+ synchronized(data.waitFor) {
+ data.waitFor.notifyAll();
+ }
+ for (int i = 0; i < N; i++) {
+ threads[i].join();
+ }
+
+ RETAIN.clear();
+ }
+
public static void print(String[][] stack) {
System.out.println("---------");
for (String[] stackElement : stack) {
@@ -124,6 +183,42 @@ public class Main {
print(getStackTrace(t, start, max));
}
+ public static void printAll(Object[][] stacks) {
+ List<String> stringified = new ArrayList<String>(stacks.length);
+
+ for (Object[] stackInfo : stacks) {
+ Thread t = (Thread)stackInfo[0];
+ String name = (t != null) ? t.getName() : "null";
+ String stackSerialization;
+ if (name.contains("Daemon")) {
+ // Do not print daemon stacks, as they're non-deterministic.
+ stackSerialization = "<not printed>";
+ } else {
+ StringBuilder sb = new StringBuilder();
+ for (String[] stackElement : (String[][])stackInfo[1]) {
+ for (String part : stackElement) {
+ sb.append(' ');
+ sb.append(part);
+ }
+ sb.append('\n');
+ }
+ stackSerialization = sb.toString();
+ }
+ stringified.add(name + "\n" + stackSerialization);
+ }
+
+ Collections.sort(stringified);
+
+ for (String s : stringified) {
+ System.out.println("---------");
+ System.out.println(s);
+ }
+ }
+
+ public static void printAll(int max) {
+ printAll(getAllStackTraces(max));
+ }
+
// Wrap generated stack traces into a class to separate them nicely.
public static class Recurse {
@@ -170,10 +265,22 @@ public class Main {
}
public static class ControlData {
- CountDownLatch reached = new CountDownLatch(1);
+ CountDownLatch reached;
Object waitFor = null;
volatile boolean stop = false;
+
+ public ControlData() {
+ this(1);
+ }
+
+ public ControlData(int latchCount) {
+ reached = new CountDownLatch(latchCount);
+ }
}
public static native String[][] getStackTrace(Thread thread, int start, int max);
+ // Get all stack traces. This will return an array with an element for each thread. The element
+ // is an array itself with the first element being the thread, and the second element a nested
+ // String array as in getStackTrace.
+ public static native Object[][] getAllStackTraces(int max);
}
diff --git a/test/911-get-stack-trace/stack_trace.cc b/test/911-get-stack-trace/stack_trace.cc
index b3e8bc3b1f..57d4f6d2ee 100644
--- a/test/911-get-stack-trace/stack_trace.cc
+++ b/test/911-get-stack-trace/stack_trace.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "stack_trace.h"
-
#include <inttypes.h>
#include <memory>
#include <stdio.h>
@@ -52,22 +50,9 @@ static jint FindLineNumber(jint line_number_count,
return line_number;
}
-extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getStackTrace(
- JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thread, jint start, jint max) {
- std::unique_ptr<jvmtiFrameInfo[]> frames(new jvmtiFrameInfo[max]);
-
- jint count;
- {
- jvmtiError result = jvmti_env->GetStackTrace(thread, start, max, frames.get(), &count);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetStackTrace: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- return nullptr;
- }
- }
-
+static jobjectArray TranslateJvmtiFrameInfoArray(JNIEnv* env,
+ jvmtiFrameInfo* frames,
+ jint count) {
auto callback = [&](jint method_index) -> jobjectArray {
char* name;
char* sig;
@@ -142,16 +127,57 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getStackTrace(
return CreateObjectArray(env, count, "[Ljava/lang/String;", callback);
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getStackTrace(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thread, jint start, jint max) {
+ std::unique_ptr<jvmtiFrameInfo[]> frames(new jvmtiFrameInfo[max]);
+
+ jint count;
+ {
+ jvmtiError result = jvmti_env->GetStackTrace(thread, start, max, frames.get(), &count);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running GetStackTrace: %s\n", err);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ return nullptr;
+ }
+ }
+
+ return TranslateJvmtiFrameInfoArray(env, frames.get(), count);
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getAllStackTraces(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jint max) {
+ std::unique_ptr<jvmtiFrameInfo[]> frames(new jvmtiFrameInfo[max]);
+
+ jint thread_count;
+ jvmtiStackInfo* stack_infos;
+ {
+ jvmtiError result = jvmti_env->GetAllStackTraces(max, &stack_infos, &thread_count);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running GetAllStackTraces: %s\n", err);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ return nullptr;
+ }
}
- SetAllCapabilities(jvmti_env);
- return 0;
+
+ auto callback = [&](jint thread_index) -> jobject {
+ auto inner_callback = [&](jint index) -> jobject {
+ if (index == 0) {
+ return stack_infos[thread_index].thread;
+ } else {
+ return TranslateJvmtiFrameInfoArray(env,
+ stack_infos[thread_index].frame_buffer,
+ stack_infos[thread_index].frame_count);
+ }
+ };
+ return CreateObjectArray(env, 2, "java/lang/Object", inner_callback);
+ };
+ jobjectArray ret = CreateObjectArray(env, thread_count, "[Ljava/lang/Object;", callback);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(stack_infos));
+ return ret;
}
} // namespace Test911GetStackTrace
diff --git a/test/911-get-stack-trace/stack_trace.h b/test/911-get-stack-trace/stack_trace.h
deleted file mode 100644
index eba2a91da1..0000000000
--- a/test/911-get-stack-trace/stack_trace.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_911_GET_STACK_TRACE_STACK_TRACE_H_
-#define ART_TEST_911_GET_STACK_TRACE_STACK_TRACE_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test911GetStackTrace {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test911GetStackTrace
-} // namespace art
-
-#endif // ART_TEST_911_GET_STACK_TRACE_STACK_TRACE_H_
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index 38a4f0e337..69301c7925 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "classes.h"
-
#include <stdio.h>
#include "base/macros.h"
@@ -224,17 +222,5 @@ extern "C" JNIEXPORT jobject JNICALL Java_Main_getClassLoader(
return classloader;
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test912Classes
} // namespace art
diff --git a/test/912-classes/classes.h b/test/912-classes/classes.h
deleted file mode 100644
index 62fb203356..0000000000
--- a/test/912-classes/classes.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_912_CLASSES_CLASSES_H_
-#define ART_TEST_912_CLASSES_CLASSES_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test912Classes {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test912Classes
-} // namespace art
-
-#endif // ART_TEST_912_CLASSES_CLASSES_H_
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index 0b232af0df..67599192cf 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "heaps.h"
-
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
@@ -495,17 +493,5 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_followReferences(JNIEnv* env
return ret;
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test913Heaps
} // namespace art
diff --git a/test/913-heaps/heaps.h b/test/913-heaps/heaps.h
deleted file mode 100644
index bd828aca33..0000000000
--- a/test/913-heaps/heaps.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_913_HEAPS_HEAPS_H_
-#define ART_TEST_913_HEAPS_HEAPS_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test913Heaps {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test913Heaps
-} // namespace art
-
-#endif // ART_TEST_913_HEAPS_HEAPS_H_
diff --git a/test/918-fields/fields.cc b/test/918-fields/fields.cc
index 4d2b34b94e..7d29912f47 100644
--- a/test/918-fields/fields.cc
+++ b/test/918-fields/fields.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "fields.h"
-
#include <stdio.h>
#include "base/macros.h"
@@ -132,17 +130,5 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isFieldSynthetic(
return synth;
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test918Fields
} // namespace art
diff --git a/test/918-fields/fields.h b/test/918-fields/fields.h
deleted file mode 100644
index 89bd1614d5..0000000000
--- a/test/918-fields/fields.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_918_FIELDS_FIELDS_H_
-#define ART_TEST_918_FIELDS_FIELDS_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test918Fields {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test918Fields
-} // namespace art
-
-#endif // ART_TEST_918_FIELDS_FIELDS_H_
diff --git a/test/920-objects/objects.cc b/test/920-objects/objects.cc
index 886dd0e673..0553a9d007 100644
--- a/test/920-objects/objects.cc
+++ b/test/920-objects/objects.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "objects.h"
-
#include <stdio.h>
#include "base/macros.h"
@@ -61,17 +59,5 @@ extern "C" JNIEXPORT jint JNICALL Java_Main_getObjectHashCode(
return hash;
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test920Objects
} // namespace art
diff --git a/test/920-objects/objects.h b/test/920-objects/objects.h
deleted file mode 100644
index 5f21e7b7cb..0000000000
--- a/test/920-objects/objects.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_920_OBJECTS_OBJECTS_H_
-#define ART_TEST_920_OBJECTS_OBJECTS_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test920Objects {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test920Objects
-} // namespace art
-
-#endif // ART_TEST_920_OBJECTS_OBJECTS_H_
diff --git a/test/922-properties/properties.cc b/test/922-properties/properties.cc
index b1e7fce3b5..cb732c74f1 100644
--- a/test/922-properties/properties.cc
+++ b/test/922-properties/properties.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "properties.h"
-
#include <stdio.h>
#include "base/macros.h"
@@ -91,17 +89,5 @@ extern "C" JNIEXPORT void JNICALL Java_Main_setSystemProperty(
}
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test922Properties
} // namespace art
diff --git a/test/922-properties/properties.h b/test/922-properties/properties.h
deleted file mode 100644
index 84feb10758..0000000000
--- a/test/922-properties/properties.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_922_PROPERTIES_PROPERTIES_H_
-#define ART_TEST_922_PROPERTIES_PROPERTIES_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test922Properties {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test922Properties
-} // namespace art
-
-#endif // ART_TEST_922_PROPERTIES_PROPERTIES_H_
diff --git a/test/923-monitors/monitors.cc b/test/923-monitors/monitors.cc
index 2aa36cbdba..4baa530ec2 100644
--- a/test/923-monitors/monitors.cc
+++ b/test/923-monitors/monitors.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "monitors.h"
-
#include <stdio.h>
#include "base/macros.h"
@@ -84,17 +82,5 @@ extern "C" JNIEXPORT void JNICALL Java_Main_rawMonitorNotifyAll(
JvmtiErrorToException(env, result);
}
-// Don't do anything
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- SetAllCapabilities(jvmti_env);
- return 0;
-}
-
} // namespace Test923Monitors
} // namespace art
diff --git a/test/923-monitors/monitors.h b/test/923-monitors/monitors.h
deleted file mode 100644
index 14cd5cd633..0000000000
--- a/test/923-monitors/monitors.h
+++ /dev/null
@@ -1,30 +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.
- */
-
-#ifndef ART_TEST_923_MONITORS_MONITORS_H_
-#define ART_TEST_923_MONITORS_MONITORS_H_
-
-#include <jni.h>
-
-namespace art {
-namespace Test923Monitors {
-
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
-} // namespace Test923Monitors
-} // namespace art
-
-#endif // ART_TEST_923_MONITORS_MONITORS_H_
diff --git a/test/924-threads/build b/test/924-threads/build
new file mode 100755
index 0000000000..898e2e54a2
--- /dev/null
+++ b/test/924-threads/build
@@ -0,0 +1,17 @@
+#!/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-build "$@" --experimental agents
diff --git a/test/924-threads/expected.txt b/test/924-threads/expected.txt
new file mode 100644
index 0000000000..54065223cf
--- /dev/null
+++ b/test/924-threads/expected.txt
@@ -0,0 +1,30 @@
+currentThread OK
+main
+5
+false
+java.lang.ThreadGroup[name=main,maxpri=10]
+class dalvik.system.PathClassLoader
+main
+5
+false
+java.lang.ThreadGroup[name=main,maxpri=10]
+class dalvik.system.PathClassLoader
+Daemon Thread
+5
+true
+java.lang.ThreadGroup[name=main,maxpri=10]
+class dalvik.system.PathClassLoader
+Daemon Thread
+5
+true
+java.lang.ThreadGroup[name=main,maxpri=10]
+class dalvik.system.PathClassLoader
+5
+5
+0 = NEW
+191 = ALIVE|WAITING_INDEFINITELY|WAITING|IN_OBJECT_WAIT
+1a1 = ALIVE|WAITING_WITH_TIMEOUT|WAITING|IN_OBJECT_WAIT
+401 = ALIVE|BLOCKED_ON_MONITOR_ENTER
+e1 = ALIVE|WAITING_WITH_TIMEOUT|SLEEPING|WAITING
+5 = ALIVE|RUNNABLE
+2 = TERMINATED
diff --git a/test/924-threads/info.txt b/test/924-threads/info.txt
new file mode 100644
index 0000000000..875a5f6ec1
--- /dev/null
+++ b/test/924-threads/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/924-threads/run b/test/924-threads/run
new file mode 100755
index 0000000000..4379349cb2
--- /dev/null
+++ b/test/924-threads/run
@@ -0,0 +1,19 @@
+#!/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 "$@" --experimental agents \
+ --experimental runtime-plugins \
+ --jvmti
diff --git a/test/924-threads/src/Main.java b/test/924-threads/src/Main.java
new file mode 100644
index 0000000000..048766604f
--- /dev/null
+++ b/test/924-threads/src/Main.java
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.concurrent.CountDownLatch;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[1]);
+
+ doTest();
+ }
+
+ private static void doTest() throws Exception {
+ Thread t1 = Thread.currentThread();
+ Thread t2 = getCurrentThread();
+
+ if (t1 != t2) {
+ throw new RuntimeException("Expected " + t1 + " but got " + t2);
+ }
+ System.out.println("currentThread OK");
+
+ printThreadInfo(t1);
+ printThreadInfo(null);
+
+ Thread t3 = new Thread("Daemon Thread");
+ t3.setDaemon(true);
+ // Do not start this thread, yet.
+ printThreadInfo(t3);
+ // Start, and wait for it to die.
+ t3.start();
+ t3.join();
+ Thread.sleep(500); // Wait a little bit.
+ // Thread has died, check that we can still get info.
+ printThreadInfo(t3);
+
+ doStateTests();
+ }
+
+ private static class Holder {
+ volatile boolean flag = false;
+ }
+
+ private static void doStateTests() throws Exception {
+ System.out.println(Integer.toHexString(getThreadState(null)));
+ System.out.println(Integer.toHexString(getThreadState(Thread.currentThread())));
+
+ final CountDownLatch cdl1 = new CountDownLatch(1);
+ final CountDownLatch cdl2 = new CountDownLatch(1);
+ final CountDownLatch cdl3_1 = new CountDownLatch(1);
+ final CountDownLatch cdl3_2 = new CountDownLatch(1);
+ final CountDownLatch cdl4 = new CountDownLatch(1);
+ final CountDownLatch cdl5 = new CountDownLatch(1);
+ final Holder h = new Holder();
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ cdl1.countDown();
+ synchronized(cdl1) {
+ cdl1.wait();
+ }
+
+ cdl2.countDown();
+ synchronized(cdl2) {
+ cdl2.wait(1000); // Wait a second.
+ }
+
+ cdl3_1.await();
+ cdl3_2.countDown();
+ synchronized(cdl3_2) {
+ // Nothing, just wanted to block on cdl3.
+ }
+
+ cdl4.countDown();
+ Thread.sleep(1000);
+
+ cdl5.countDown();
+ while (!h.flag) {
+ // Busy-loop.
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+ Thread t = new Thread(r);
+ printThreadState(t);
+ t.start();
+
+ // Waiting.
+ cdl1.await();
+ Thread.yield();
+ Thread.sleep(100);
+ printThreadState(t);
+ synchronized(cdl1) {
+ cdl1.notifyAll();
+ }
+
+ // Timed waiting.
+ cdl2.await();
+ Thread.yield();
+ Thread.sleep(100);
+ printThreadState(t);
+ synchronized(cdl2) {
+ cdl2.notifyAll();
+ }
+
+ // Blocked on monitor.
+ synchronized(cdl3_2) {
+ cdl3_1.countDown();
+ cdl3_2.await();
+ Thread.yield();
+ Thread.sleep(100);
+ printThreadState(t);
+ }
+
+ // Sleeping.
+ cdl4.await();
+ Thread.yield();
+ Thread.sleep(100);
+ printThreadState(t);
+
+ // Running.
+ cdl5.await();
+ Thread.yield();
+ Thread.sleep(100);
+ printThreadState(t);
+ h.flag = true;
+
+ // Dying.
+ t.join();
+ Thread.yield();
+ Thread.sleep(100);
+
+ printThreadState(t);
+ }
+
+ private final static Map<Integer, String> STATE_NAMES = new HashMap<Integer, String>();
+ private final static List<Integer> STATE_KEYS = new ArrayList<Integer>();
+ static {
+ STATE_NAMES.put(0x1, "ALIVE");
+ STATE_NAMES.put(0x2, "TERMINATED");
+ STATE_NAMES.put(0x4, "RUNNABLE");
+ STATE_NAMES.put(0x400, "BLOCKED_ON_MONITOR_ENTER");
+ STATE_NAMES.put(0x80, "WAITING");
+ STATE_NAMES.put(0x10, "WAITING_INDEFINITELY");
+ STATE_NAMES.put(0x20, "WAITING_WITH_TIMEOUT");
+ STATE_NAMES.put(0x40, "SLEEPING");
+ STATE_NAMES.put(0x100, "IN_OBJECT_WAIT");
+ STATE_NAMES.put(0x200, "PARKED");
+ STATE_NAMES.put(0x100000, "SUSPENDED");
+ STATE_NAMES.put(0x200000, "INTERRUPTED");
+ STATE_NAMES.put(0x400000, "IN_NATIVE");
+ STATE_KEYS.addAll(STATE_NAMES.keySet());
+ Collections.sort(STATE_KEYS);
+ }
+
+ private static void printThreadState(Thread t) {
+ int state = getThreadState(t);
+
+ StringBuilder sb = new StringBuilder();
+
+ for (Integer i : STATE_KEYS) {
+ if ((state & i) != 0) {
+ if (sb.length()>0) {
+ sb.append('|');
+ }
+ sb.append(STATE_NAMES.get(i));
+ }
+ }
+
+ if (sb.length() == 0) {
+ sb.append("NEW");
+ }
+
+ System.out.println(Integer.toHexString(state) + " = " + sb.toString());
+ }
+
+ private static void printThreadInfo(Thread t) {
+ Object[] threadInfo = getThreadInfo(t);
+ if (threadInfo == null || threadInfo.length != 5) {
+ System.out.println(Arrays.toString(threadInfo));
+ throw new RuntimeException("threadInfo length wrong");
+ }
+
+ System.out.println(threadInfo[0]); // Name
+ System.out.println(threadInfo[1]); // Priority
+ System.out.println(threadInfo[2]); // Daemon
+ System.out.println(threadInfo[3]); // Threadgroup
+ System.out.println(threadInfo[4] == null ? "null" : threadInfo[4].getClass()); // Context CL.
+ }
+
+ private static native Thread getCurrentThread();
+ private static native Object[] getThreadInfo(Thread t);
+ private static native int getThreadState(Thread t);
+}
diff --git a/test/924-threads/threads.cc b/test/924-threads/threads.cc
new file mode 100644
index 0000000000..4abf8fcf93
--- /dev/null
+++ b/test/924-threads/threads.cc
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include "android-base/stringprintf.h"
+#include "base/macros.h"
+#include "base/logging.h"
+#include "jni.h"
+#include "openjdkjvmti/jvmti.h"
+#include "ScopedLocalRef.h"
+
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
+namespace art {
+namespace Test924Threads {
+
+// private static native Thread getCurrentThread();
+// private static native Object[] getThreadInfo(Thread t);
+
+extern "C" JNIEXPORT jthread JNICALL Java_Main_getCurrentThread(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
+ jthread thread = nullptr;
+ jvmtiError result = jvmti_env->GetCurrentThread(&thread);
+ if (JvmtiErrorToException(env, result)) {
+ return nullptr;
+ }
+ return thread;
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getThreadInfo(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jthread thread) {
+ jvmtiThreadInfo info;
+ memset(&info, 0, sizeof(jvmtiThreadInfo));
+
+ jvmtiError result = jvmti_env->GetThreadInfo(thread, &info);
+ if (JvmtiErrorToException(env, result)) {
+ return nullptr;
+ }
+
+ auto callback = [&](jint component_index) -> jobject {
+ switch (component_index) {
+ // The name.
+ case 0:
+ return (info.name == nullptr) ? nullptr : env->NewStringUTF(info.name);
+
+ // The priority. Use a string for simplicity of construction.
+ case 1:
+ return env->NewStringUTF(android::base::StringPrintf("%d", info.priority).c_str());
+
+ // Whether it's a daemon. Use a string for simplicity of construction.
+ case 2:
+ return env->NewStringUTF(info.is_daemon == JNI_TRUE ? "true" : "false");
+
+ // The thread group;
+ case 3:
+ return env->NewLocalRef(info.thread_group);
+
+ // The context classloader.
+ case 4:
+ return env->NewLocalRef(info.context_class_loader);
+ }
+ LOG(FATAL) << "Should not reach here";
+ UNREACHABLE();
+ };
+ jobjectArray ret = CreateObjectArray(env, 5, "java/lang/Object", callback);
+
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(info.name));
+ if (info.thread_group != nullptr) {
+ env->DeleteLocalRef(info.thread_group);
+ }
+ if (info.context_class_loader != nullptr) {
+ env->DeleteLocalRef(info.context_class_loader);
+ }
+
+ return ret;
+}
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_getThreadState(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jthread thread) {
+ jint state;
+ jvmtiError result = jvmti_env->GetThreadState(thread, &state);
+ if (JvmtiErrorToException(env, result)) {
+ return 0;
+ }
+ return state;
+}
+
+} // namespace Test924Threads
+} // namespace art
diff --git a/test/Android.bp b/test/Android.bp
index a223c3aa29..b0f0e5a98d 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -264,6 +264,7 @@ art_cc_defaults {
"920-objects/objects.cc",
"922-properties/properties.cc",
"923-monitors/monitors.cc",
+ "924-threads/threads.cc",
],
shared_libs: [
"libbase",
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index fd3a897dae..dd7876f09d 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -296,6 +296,7 @@ TEST_ART_BROKEN_TARGET_TESTS += \
921-hello-failure \
922-properties \
923-monitors \
+ 924-threads \
ifneq (,$(filter target,$(TARGET_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
@@ -721,6 +722,16 @@ endif
TEST_ART_BROKEN_OPTIMIZING_HEAP_POISONING_RUN_TESTS :=
+# Tests that check semantics for a non-debuggable app.
+TEST_ART_BROKEN_DEBUGGABLE_RUN_TESTS := \
+ 909-attach-agent \
+
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+ $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+ $(IMAGE_TYPES),$(PICTEST_TYPES),debuggable,$(TEST_ART_BROKEN_DEBUGGABLE_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+
+TEST_ART_BROKEN_DEBUGGABLE_RUN_TESTS :=
+
# Tests incompatible with bisection bug search. Sorted by incompatibility reason.
# 000 through 595 do not compile anything. 089 tests a build failure. 018 through 137
# run dalvikvm more than once. 115 and 088 assume they are always compiled.
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index 33e132103e..8abd063a01 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -26,21 +26,7 @@
#include "common_helper.h"
#include "901-hello-ti-agent/basics.h"
-#include "903-hello-tagging/tagging.h"
-#include "904-object-allocation/tracking.h"
-#include "905-object-free/tracking_free.h"
-#include "906-iterate-heap/iterate_heap.h"
-#include "907-get-loaded-classes/get_loaded_classes.h"
-#include "908-gc-start-finish/gc_callbacks.h"
#include "909-attach-agent/attach.h"
-#include "910-methods/methods.h"
-#include "911-get-stack-trace/stack_trace.h"
-#include "912-classes/classes.h"
-#include "913-heaps/heaps.h"
-#include "918-fields/fields.h"
-#include "920-objects/objects.h"
-#include "922-properties/properties.h"
-#include "923-monitors/monitors.h"
namespace art {
@@ -55,31 +41,30 @@ struct AgentLib {
OnAttach attach;
};
-// A list of all the agents we have for testing.
+// A trivial OnLoad implementation that only initializes the global jvmti_env.
+static jint MinimalOnLoad(JavaVM* vm,
+ char* options ATTRIBUTE_UNUSED,
+ void* reserved ATTRIBUTE_UNUSED) {
+ if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
+ printf("Unable to get jvmti env!\n");
+ return 1;
+ }
+ SetAllCapabilities(jvmti_env);
+ return 0;
+}
+
+// A list of all non-standard the agents we have for testing. All other agents will use
+// MinimalOnLoad.
AgentLib agents[] = {
{ "901-hello-ti-agent", Test901HelloTi::OnLoad, nullptr },
{ "902-hello-transformation", common_redefine::OnLoad, nullptr },
- { "903-hello-tagging", Test903HelloTagging::OnLoad, nullptr },
- { "904-object-allocation", Test904ObjectAllocation::OnLoad, nullptr },
- { "905-object-free", Test905ObjectFree::OnLoad, nullptr },
- { "906-iterate-heap", Test906IterateHeap::OnLoad, nullptr },
- { "907-get-loaded-classes", Test907GetLoadedClasses::OnLoad, nullptr },
- { "908-gc-start-finish", Test908GcStartFinish::OnLoad, nullptr },
{ "909-attach-agent", nullptr, Test909AttachAgent::OnAttach },
- { "910-methods", Test910Methods::OnLoad, nullptr },
- { "911-get-stack-trace", Test911GetStackTrace::OnLoad, nullptr },
- { "912-classes", Test912Classes::OnLoad, nullptr },
- { "913-heaps", Test913Heaps::OnLoad, nullptr },
{ "914-hello-obsolescence", common_redefine::OnLoad, nullptr },
{ "915-obsolete-2", common_redefine::OnLoad, nullptr },
{ "916-obsolete-jit", common_redefine::OnLoad, nullptr },
{ "917-fields-transformation", common_redefine::OnLoad, nullptr },
- { "918-fields", Test918Fields::OnLoad, nullptr },
{ "919-obsolete-fields", common_redefine::OnLoad, nullptr },
- { "920-objects", Test920Objects::OnLoad, nullptr },
{ "921-hello-failure", common_redefine::OnLoad, nullptr },
- { "922-properties", Test922Properties::OnLoad, nullptr },
- { "923-monitors", Test923Monitors::OnLoad, nullptr },
};
static AgentLib* FindAgent(char* name) {
@@ -120,18 +105,21 @@ extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void*
printf("Unable to find agent name in options: %s\n", options);
return -1;
}
+
+ SetIsJVM(remaining_options);
+
AgentLib* lib = FindAgent(name_option);
+ OnLoad fn = nullptr;
if (lib == nullptr) {
- printf("Unable to find agent named: %s, add it to the list in test/ti-agent/common_load.cc\n",
- name_option);
- return -2;
- }
- if (lib->load == nullptr) {
- printf("agent: %s does not include an OnLoad method.\n", name_option);
- return -3;
+ fn = &MinimalOnLoad;
+ } else {
+ if (lib->load == nullptr) {
+ printf("agent: %s does not include an OnLoad method.\n", name_option);
+ return -3;
+ }
+ fn = lib->load;
}
- SetIsJVM(remaining_options);
- return lib->load(vm, remaining_options, reserved);
+ return fn(vm, remaining_options, reserved);
}
extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {