diff options
49 files changed, 621 insertions, 174 deletions
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 96f17accad..e323b1684a 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -207,8 +207,8 @@ TEST_F(CompilerDriverMethodsTest, Selection) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); ScopedObjectAccess soa(self); StackHandleScope<1> hs(self); - Handle<mirror::ClassLoader> h_loader(hs.NewHandle( - reinterpret_cast<mirror::ClassLoader*>(self->DecodeJObject(class_loader)))); + Handle<mirror::ClassLoader> h_loader( + hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); mirror::Class* klass = class_linker->FindClass(self, "LStaticLeafMethods;", h_loader); ASSERT_NE(klass, nullptr); @@ -265,8 +265,8 @@ class CompilerDriverProfileTest : public CompilerDriverTest { Thread* self = Thread::Current(); ScopedObjectAccess soa(self); StackHandleScope<1> hs(self); - Handle<mirror::ClassLoader> h_loader(hs.NewHandle( - reinterpret_cast<mirror::ClassLoader*>(self->DecodeJObject(class_loader)))); + Handle<mirror::ClassLoader> h_loader( + hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); mirror::Class* klass = class_linker->FindClass(self, clazz.c_str(), h_loader); ASSERT_NE(klass, nullptr); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 66938b2e07..8ae04a1e49 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -433,9 +433,9 @@ void ImageWriter::PrepareDexCacheArraySlots() { Thread* const self = Thread::Current(); ReaderMutexLock mu(self, *class_linker->DexLock()); for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { - mirror::DexCache* dex_cache = - down_cast<mirror::DexCache*>(self->DecodeJObject(data.weak_root)); - if (dex_cache == nullptr || IsInBootImage(dex_cache)) { + ObjPtr<mirror::DexCache> dex_cache = + ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); + if (dex_cache == nullptr || IsInBootImage(dex_cache.Ptr())) { continue; } const DexFile* dex_file = dex_cache->GetDexFile(); @@ -464,7 +464,9 @@ void ImageWriter::PrepareDexCacheArraySlots() { } } -void ImageWriter::AddDexCacheArrayRelocation(void* array, size_t offset, DexCache* dex_cache) { +void ImageWriter::AddDexCacheArrayRelocation(void* array, + size_t offset, + ObjPtr<mirror::DexCache> dex_cache) { if (array != nullptr) { DCHECK(!IsInBootImage(array)); size_t oat_index = GetOatIndexForDexCache(dex_cache); @@ -878,7 +880,7 @@ void ImageWriter::PruneNonImageClasses() { if (self->IsJWeakCleared(data.weak_root)) { continue; } - mirror::DexCache* dex_cache = self->DecodeJObject(data.weak_root)->AsDexCache(); + ObjPtr<mirror::DexCache> dex_cache = self->DecodeJObject(data.weak_root)->AsDexCache(); for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) { Class* klass = dex_cache->GetResolvedType(i); if (klass != nullptr && !KeepClass(klass)) { @@ -1005,13 +1007,13 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const { ReaderMutexLock mu(self, *class_linker->DexLock()); // Count number of dex caches not in the boot image. for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { - mirror::DexCache* dex_cache = - down_cast<mirror::DexCache*>(self->DecodeJObject(data.weak_root)); + ObjPtr<mirror::DexCache> dex_cache = + ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); if (dex_cache == nullptr) { continue; } const DexFile* dex_file = dex_cache->GetDexFile(); - if (!IsInBootImage(dex_cache)) { + if (!IsInBootImage(dex_cache.Ptr())) { dex_cache_count += image_dex_files.find(dex_file) != image_dex_files.end() ? 1u : 0u; } } @@ -1024,13 +1026,13 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const { size_t non_image_dex_caches = 0; // Re-count number of non image dex caches. for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { - mirror::DexCache* dex_cache = - down_cast<mirror::DexCache*>(self->DecodeJObject(data.weak_root)); + ObjPtr<mirror::DexCache> dex_cache = + ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); if (dex_cache == nullptr) { continue; } const DexFile* dex_file = dex_cache->GetDexFile(); - if (!IsInBootImage(dex_cache)) { + if (!IsInBootImage(dex_cache.Ptr())) { non_image_dex_caches += image_dex_files.find(dex_file) != image_dex_files.end() ? 1u : 0u; } } @@ -1038,14 +1040,15 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const { << "The number of non-image dex caches changed."; size_t i = 0; for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { - mirror::DexCache* dex_cache = - down_cast<mirror::DexCache*>(self->DecodeJObject(data.weak_root)); + ObjPtr<mirror::DexCache> dex_cache = + ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); if (dex_cache == nullptr) { continue; } const DexFile* dex_file = dex_cache->GetDexFile(); - if (!IsInBootImage(dex_cache) && image_dex_files.find(dex_file) != image_dex_files.end()) { - dex_caches->Set<false>(i, dex_cache); + if (!IsInBootImage(dex_cache.Ptr()) && + image_dex_files.find(dex_file) != image_dex_files.end()) { + dex_caches->Set<false>(i, dex_cache.Ptr()); ++i; } } @@ -2384,12 +2387,10 @@ size_t ImageWriter::GetOatIndexForDexFile(const DexFile* dex_file) const { return it->second; } -size_t ImageWriter::GetOatIndexForDexCache(mirror::DexCache* dex_cache) const { - if (dex_cache == nullptr) { - return GetDefaultOatIndex(); - } else { - return GetOatIndexForDexFile(dex_cache->GetDexFile()); - } +size_t ImageWriter::GetOatIndexForDexCache(ObjPtr<mirror::DexCache> dex_cache) const { + return (dex_cache == nullptr) + ? GetDefaultOatIndex() + : GetOatIndexForDexFile(dex_cache->GetDexFile()); } void ImageWriter::UpdateOatFileLayout(size_t oat_index, diff --git a/compiler/image_writer.h b/compiler/image_writer.h index acd16813cb..c9cf4cbc1b 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -132,7 +132,7 @@ class ImageWriter FINAL { size_t GetOatIndexForDexFile(const DexFile* dex_file) const; // Get the index of the oat file containing the dex file served by the dex cache. - size_t GetOatIndexForDexCache(mirror::DexCache* dex_cache) const + size_t GetOatIndexForDexCache(ObjPtr<mirror::DexCache> dex_cache) const REQUIRES_SHARED(Locks::mutator_lock_); // Update the oat layout for the given oat file. @@ -334,7 +334,7 @@ class ImageWriter FINAL { REQUIRES_SHARED(Locks::mutator_lock_); BinSlot GetImageBinSlot(mirror::Object* object) const REQUIRES_SHARED(Locks::mutator_lock_); - void AddDexCacheArrayRelocation(void* array, size_t offset, mirror::DexCache* dex_cache) + void AddDexCacheArrayRelocation(void* array, size_t offset, ObjPtr<mirror::DexCache> dex_cache) REQUIRES_SHARED(Locks::mutator_lock_); void AddMethodPointerArray(mirror::PointerArray* arr) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc index 6b56fe0b7f..36e252742c 100644 --- a/compiler/jni/jni_compiler_test.cc +++ b/compiler/jni/jni_compiler_test.cc @@ -523,8 +523,7 @@ bool ScopedDisableCheckNumStackReferences::sCheckNumStackReferences = true; // Check that the handle scope at the start of this block is the same as the handle scope at the end of the block. struct ScopedCheckHandleScope { - ScopedCheckHandleScope() { - handle_scope_ = Thread::Current()->GetTopHandleScope(); + ScopedCheckHandleScope() : handle_scope_(Thread::Current()->GetTopHandleScope()) { } ~ScopedCheckHandleScope() { @@ -533,7 +532,7 @@ struct ScopedCheckHandleScope { << "invocations have finished (as before they were invoked)."; } - HandleScope* handle_scope_; + HandleScope* const handle_scope_; }; static void expectNumStackReferences(size_t val1, size_t val2) { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index d6006b2424..f75841415e 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1575,10 +1575,10 @@ class ImageDumper { { ReaderMutexLock mu(self, *class_linker->DexLock()); for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { - mirror::DexCache* dex_cache = - down_cast<mirror::DexCache*>(self->DecodeJObject(data.weak_root)); + ObjPtr<mirror::DexCache> dex_cache = + ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); if (dex_cache != nullptr) { - dex_caches_.insert(dex_cache); + dex_caches_.insert(dex_cache.Ptr()); } } } diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc index 4dc7b317cd..8a51dc2c04 100644 --- a/runtime/check_jni.cc +++ b/runtime/check_jni.cc @@ -772,7 +772,7 @@ class ScopedCheck { okay = false; } else { obj = soa.Vm()->DecodeWeakGlobal(soa.Self(), ref); - okay = Runtime::Current()->IsClearedJniWeakGlobal(obj.Ptr()); + okay = Runtime::Current()->IsClearedJniWeakGlobal(obj); } if (!okay) { AbortF("%s is an invalid %s: %p (%p)", diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 378da57bba..fa971c4c2b 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -26,6 +26,7 @@ #include "mirror/iftable.h" #include "mirror/object_array.h" #include "handle_scope-inl.h" +#include "scoped_thread_state_change-inl.h" #include <atomic> @@ -247,8 +248,8 @@ ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, ArtMethod if (!self->IsJWeakCleared(data.weak_root) && proxy_method->HasSameDexCacheResolvedTypes(data.resolved_types, image_pointer_size_)) { - mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>( - self->DecodeJObject(data.weak_root)); + ObjPtr<mirror::DexCache> dex_cache = + ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); if (dex_cache != nullptr) { ArtMethod* resolved_method = dex_cache->GetResolvedMethod( proxy_method->GetDexMethodIndex(), image_pointer_size_); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 7aa28d36be..48d31a4c3e 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3341,13 +3341,12 @@ mirror::DexCache* ClassLinker::FindDexCacheLocked(Thread* self, for (const DexCacheData& data : dex_caches_) { // Avoid decoding (and read barriers) other unrelated dex caches. if (data.dex_file == &dex_file) { - mirror::DexCache* dex_cache = - down_cast<mirror::DexCache*>(self->DecodeJObject(data.weak_root)); + ObjPtr<mirror::DexCache> dex_cache = + ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); if (dex_cache != nullptr) { - return dex_cache; - } else { - break; + return dex_cache.Ptr(); } + break; } } if (allow_failure) { @@ -3356,7 +3355,8 @@ mirror::DexCache* ClassLinker::FindDexCacheLocked(Thread* self, std::string location(dex_file.GetLocation()); // Failure, dump diagnostic and abort. for (const DexCacheData& data : dex_caches_) { - mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(data.weak_root)); + ObjPtr<mirror::DexCache> dex_cache = + ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); if (dex_cache != nullptr) { LOG(ERROR) << "Registered dex file " << dex_cache->GetDexFile()->GetLocation(); } @@ -3370,7 +3370,7 @@ void ClassLinker::FixupDexCaches(ArtMethod* resolution_method) { ReaderMutexLock mu(self, dex_lock_); for (const DexCacheData& data : dex_caches_) { if (!self->IsJWeakCleared(data.weak_root)) { - mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>( + ObjPtr<mirror::DexCache> dex_cache = ObjPtr<mirror::DexCache>::DownCast( self->DecodeJObject(data.weak_root)); if (dex_cache != nullptr) { dex_cache->Fixup(resolution_method, image_pointer_size_); @@ -4297,11 +4297,11 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& CHECK_EQ(interfaces_sfield.GetDeclaringClass(), klass.Get()); interfaces_sfield.SetObject<false>( klass.Get(), - soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces).Ptr()); + soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)); CHECK_EQ(throws_sfield.GetDeclaringClass(), klass.Get()); throws_sfield.SetObject<false>( klass.Get(), - soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws).Ptr()); + soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws)); { // Lock on klass is released. Lock new class object. @@ -4331,9 +4331,9 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name); CHECK_EQ(klass.Get()->GetInterfaces(), - soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces).Ptr()); + soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)); CHECK_EQ(klass.Get()->GetThrows(), - soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws).Ptr()); + soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws)); } return klass.Get(); } @@ -8304,7 +8304,7 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, // Make it a global ref and return. ScopedLocalRef<jobject> local_ref( - soa.Env(), soa.Env()->AddLocalReference<jobject>(MakeObjPtr(h_path_class_loader.Get()))); + soa.Env(), soa.Env()->AddLocalReference<jobject>(h_path_class_loader.Get())); return soa.Env()->NewGlobalRef(local_ref.get()); } @@ -8341,9 +8341,10 @@ void ClassLinker::VisitClassLoaders(ClassLoaderVisitor* visitor) const { Thread* const self = Thread::Current(); for (const ClassLoaderData& data : class_loaders_) { // Need to use DecodeJObject so that we get null for cleared JNI weak globals. - auto* const class_loader = down_cast<mirror::ClassLoader*>(self->DecodeJObject(data.weak_root)); + ObjPtr<mirror::ClassLoader> class_loader = ObjPtr<mirror::ClassLoader>::DownCast( + self->DecodeJObject(data.weak_root)); if (class_loader != nullptr) { - visitor->Visit(class_loader); + visitor->Visit(class_loader.Ptr()); } } } @@ -8371,8 +8372,8 @@ void ClassLinker::CleanupClassLoaders() { for (auto it = class_loaders_.begin(); it != class_loaders_.end(); ) { const ClassLoaderData& data = *it; // Need to use DecodeJObject so that we get null for cleared JNI weak globals. - auto* const class_loader = - down_cast<mirror::ClassLoader*>(self->DecodeJObject(data.weak_root)); + ObjPtr<mirror::ClassLoader> class_loader = + ObjPtr<mirror::ClassLoader>::DownCast(self->DecodeJObject(data.weak_root)); if (class_loader != nullptr) { ++it; } else { @@ -8400,8 +8401,7 @@ std::set<DexCacheResolvedClasses> ClassLinker::GetResolvedClasses(bool ignore_bo if (soa.Self()->IsJWeakCleared(data.weak_root)) { continue; } - mirror::DexCache* dex_cache = - down_cast<mirror::DexCache*>(soa.Self()->DecodeJObject(data.weak_root)); + ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(data.weak_root); if (dex_cache == nullptr) { continue; } @@ -8468,8 +8468,7 @@ std::unordered_set<std::string> ClassLinker::GetClassDescriptorsForProfileKeys( ReaderMutexLock mu(self, *DexLock()); for (const ClassLinker::DexCacheData& data : GetDexCachesData()) { if (!self->IsJWeakCleared(data.weak_root)) { - mirror::DexCache* dex_cache = - down_cast<mirror::DexCache*>(soa.Self()->DecodeJObject(data.weak_root)); + ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(data.weak_root); if (dex_cache != nullptr) { const DexFile* dex_file = dex_cache->GetDexFile(); // There could be duplicates if two dex files with the same location are mapped. diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 546653960f..e514112382 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -875,7 +875,7 @@ TEST_F(ClassLinkerTest, LookupResolvedType) { uint32_t type_idx = klass->GetClassDef()->class_idx_; ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache(); const DexFile& dex_file = klass->GetDexFile(); - EXPECT_EQ(dex_cache->GetResolvedType(type_idx), klass.Ptr()); + EXPECT_OBJ_PTR_EQ(dex_cache->GetResolvedType(type_idx), klass); EXPECT_OBJ_PTR_EQ( class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader.Get()), klass); @@ -1298,7 +1298,7 @@ TEST_F(ClassLinkerTest, RegisterDexFileName) { { ReaderMutexLock mu(soa.Self(), *class_linker->DexLock()); for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { - dex_cache.Assign(down_cast<mirror::DexCache*>(soa.Self()->DecodeJObject(data.weak_root))); + dex_cache.Assign(soa.Self()->DecodeJObject(data.weak_root)->AsDexCache()); if (dex_cache.Get() != nullptr) { break; } diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 1e4c7725b7..7fa8cf9326 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -752,7 +752,7 @@ void ThrowStackOverflowError(Thread* self) { error_msg = "Could not create stack trace."; } // Throw the exception. - self->SetException(reinterpret_cast<mirror::Throwable*>(self->DecodeJObject(exc.get()))); + self->SetException(self->DecodeJObject(exc.get())->AsThrowable()); } else { // Could not allocate a string object. error_msg = "Couldn't throw new StackOverflowError because JNI NewStringUTF failed."; diff --git a/runtime/debugger.cc b/runtime/debugger.cc index a7feeef89f..7006f70687 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1995,7 +1995,7 @@ JDWP::JdwpError Dbg::GetThreadName(JDWP::ObjectId thread_id, std::string* name) CHECK(thread_object != nullptr) << error; ArtField* java_lang_Thread_name_field = soa.DecodeField(WellKnownClasses::java_lang_Thread_name); - ObjPtr<mirror::String> s(java_lang_Thread_name_field->GetObject(thread_object)); + ObjPtr<mirror::String> s(java_lang_Thread_name_field->GetObject(thread_object)->AsString()); if (s != nullptr) { *name = s->ToModifiedUtf8(); } diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc index 367603e1f0..f0d3909bff 100644 --- a/runtime/dex_file_annotations.cc +++ b/runtime/dex_file_annotations.cc @@ -611,7 +611,7 @@ mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass, } Handle<mirror::Object> value_object(hs.NewHandle(annotation_value.value_.GetL())); - mirror::Class* annotation_member_class = + ObjPtr<mirror::Class> annotation_member_class = WellKnownClasses::ToClass(WellKnownClasses::libcore_reflect_AnnotationMember); Handle<mirror::Object> new_member(hs.NewHandle(annotation_member_class->AllocObject(self))); mirror::Method* method_obj_ptr; diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc index 446e3431a9..7c7e2da740 100644 --- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc @@ -132,17 +132,20 @@ static mirror::Object* JniMethodEndWithReferenceHandleResult(jobject result, Thread* self) NO_THREAD_SAFETY_ANALYSIS { // Must decode before pop. The 'result' may not be valid in case of an exception, though. - mirror::Object* o = self->IsExceptionPending() ? nullptr : self->DecodeJObject(result); + ObjPtr<mirror::Object> o; + if (!self->IsExceptionPending()) { + o = self->DecodeJObject(result); + } PopLocalReferences(saved_local_ref_cookie, self); // Process result. if (UNLIKELY(self->GetJniEnv()->check_jni)) { // CheckReferenceResult can resolve types. StackHandleScope<1> hs(self); - HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&o)); + HandleWrapperObjPtr<mirror::Object> h_obj(hs.NewHandleWrapper(&o)); CheckReferenceResult(h_obj, self); } - VerifyObject(o); - return o; + VerifyObject(o.Ptr()); + return o.Ptr(); } extern mirror::Object* JniMethodEndWithReference(jobject result, diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index 8b910750bd..dabb6da116 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -1949,10 +1949,11 @@ void ConcurrentCopying::FillWithDummyObject(mirror::Object* dummy_obj, size_t by size_t data_offset = mirror::Array::DataOffset(component_size).SizeValue(); if (data_offset > byte_size) { // An int array is too big. Use java.lang.Object. - mirror::Class* java_lang_Object = WellKnownClasses::ToClass(WellKnownClasses::java_lang_Object); - AssertToSpaceInvariant(nullptr, MemberOffset(0), java_lang_Object); + ObjPtr<mirror::Class> java_lang_Object = + WellKnownClasses::ToClass(WellKnownClasses::java_lang_Object); + AssertToSpaceInvariant(nullptr, MemberOffset(0), java_lang_Object.Ptr()); CHECK_EQ(byte_size, (java_lang_Object->GetObjectSize<kVerifyNone, kWithoutReadBarrier>())); - dummy_obj->SetClass(java_lang_Object); + dummy_obj->SetClass(java_lang_Object.Ptr()); CHECK_EQ(byte_size, (dummy_obj->SizeOf<kVerifyNone, kWithoutReadBarrier>())); } else { // Use an int array. diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h index 17d7c87bd5..7778871060 100644 --- a/runtime/gc/space/space_test.h +++ b/runtime/gc/space/space_test.h @@ -62,7 +62,7 @@ class SpaceTest : public Super { byte_array_class_ = self->GetJniEnv()->NewLocalRef(byte_array_class); EXPECT_TRUE(byte_array_class_ != nullptr); } - return reinterpret_cast<mirror::Class*>(self->DecodeJObject(byte_array_class_)); + return self->DecodeJObject(byte_array_class_)->AsClass(); } mirror::Object* Alloc(space::MallocSpace* alloc_space, diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index ac5401f5d9..845fc60b12 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -914,7 +914,7 @@ void UnstartedRuntime::UnstartedDoubleDoubleToRawLongBits( result->SetJ(bit_cast<int64_t, double>(in)); } -static mirror::Object* GetDexFromDexCache(Thread* self, mirror::DexCache* dex_cache) +static ObjPtr<mirror::Object> GetDexFromDexCache(Thread* self, mirror::DexCache* dex_cache) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile* dex_file = dex_cache->GetDexFile(); if (dex_file == nullptr) { @@ -949,10 +949,10 @@ void UnstartedRuntime::UnstartedDexCacheGetDexNative( mirror::Object* src = shadow_frame->GetVRegReference(arg_offset); bool have_dex = false; if (src != nullptr) { - mirror::Object* dex = GetDexFromDexCache(self, reinterpret_cast<mirror::DexCache*>(src)); + ObjPtr<mirror::Object> dex = GetDexFromDexCache(self, src->AsDexCache()); if (dex != nullptr) { have_dex = true; - result->SetL(dex); + result->SetL(dex.Ptr()); } } if (!have_dex) { @@ -1456,7 +1456,7 @@ void UnstartedRuntime::UnstartedMethodInvoke( ScopedLocalRef<jobject> result_jobj(env, InvokeMethod(soa, java_method.get(), java_receiver.get(), java_args.get())); - result->SetL(self->DecodeJObject(result_jobj.get())); + result->SetL(self->DecodeJObject(result_jobj.get()).Ptr()); // Conservatively flag all exceptions as transaction aborts. This way we don't need to unwrap // InvocationTargetExceptions. diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc index ecd6b524df..c5f95eb6dc 100644 --- a/runtime/java_vm_ext.cc +++ b/runtime/java_vm_ext.cc @@ -538,7 +538,7 @@ jobject JavaVMExt::AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) { return nullptr; } WriterMutexLock mu(self, globals_lock_); - IndirectRef ref = globals_.Add(IRT_FIRST_SEGMENT, obj.Ptr()); + IndirectRef ref = globals_.Add(IRT_FIRST_SEGMENT, obj); return reinterpret_cast<jobject>(ref); } @@ -550,7 +550,7 @@ jweak JavaVMExt::AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) { while (UNLIKELY(!MayAccessWeakGlobals(self))) { weak_globals_add_condition_.WaitHoldingLocks(self); } - IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj.Ptr()); + IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj); return reinterpret_cast<jweak>(ref); } @@ -640,11 +640,11 @@ void JavaVMExt::BroadcastForNewWeakGlobals() { weak_globals_add_condition_.Broadcast(self); } -mirror::Object* JavaVMExt::DecodeGlobal(IndirectRef ref) { - return globals_.SynchronizedGet(ref).Ptr(); +ObjPtr<mirror::Object> JavaVMExt::DecodeGlobal(IndirectRef ref) { + return globals_.SynchronizedGet(ref); } -void JavaVMExt::UpdateGlobal(Thread* self, IndirectRef ref, mirror::Object* result) { +void JavaVMExt::UpdateGlobal(Thread* self, IndirectRef ref, ObjPtr<mirror::Object> result) { WriterMutexLock mu(self, globals_lock_); globals_.Update(ref, result); } @@ -660,7 +660,7 @@ inline bool JavaVMExt::MayAccessWeakGlobalsUnlocked(Thread* self) const { allow_accessing_weak_globals_.LoadSequentiallyConsistent(); } -mirror::Object* JavaVMExt::DecodeWeakGlobal(Thread* self, IndirectRef ref) { +ObjPtr<mirror::Object> JavaVMExt::DecodeWeakGlobal(Thread* self, IndirectRef ref) { // It is safe to access GetWeakRefAccessEnabled without the lock since CC uses checkpoints to call // SetWeakRefAccessEnabled, and the other collectors only modify allow_accessing_weak_globals_ // when the mutators are paused. @@ -669,23 +669,23 @@ mirror::Object* JavaVMExt::DecodeWeakGlobal(Thread* self, IndirectRef ref) { // if MayAccessWeakGlobals is false. DCHECK_EQ(GetIndirectRefKind(ref), kWeakGlobal); if (LIKELY(MayAccessWeakGlobalsUnlocked(self))) { - return weak_globals_.SynchronizedGet(ref).Ptr(); + return weak_globals_.SynchronizedGet(ref); } MutexLock mu(self, weak_globals_lock_); return DecodeWeakGlobalLocked(self, ref); } -mirror::Object* JavaVMExt::DecodeWeakGlobalLocked(Thread* self, IndirectRef ref) { +ObjPtr<mirror::Object> JavaVMExt::DecodeWeakGlobalLocked(Thread* self, IndirectRef ref) { if (kDebugLocking) { weak_globals_lock_.AssertHeld(self); } while (UNLIKELY(!MayAccessWeakGlobals(self))) { weak_globals_add_condition_.WaitHoldingLocks(self); } - return weak_globals_.Get(ref).Ptr(); + return weak_globals_.Get(ref); } -mirror::Object* JavaVMExt::DecodeWeakGlobalDuringShutdown(Thread* self, IndirectRef ref) { +ObjPtr<mirror::Object> JavaVMExt::DecodeWeakGlobalDuringShutdown(Thread* self, IndirectRef ref) { DCHECK_EQ(GetIndirectRefKind(ref), kWeakGlobal); DCHECK(Runtime::Current()->IsShuttingDown(self)); if (self != nullptr) { @@ -695,7 +695,7 @@ mirror::Object* JavaVMExt::DecodeWeakGlobalDuringShutdown(Thread* self, Indirect if (!kUseReadBarrier) { DCHECK(allow_accessing_weak_globals_.LoadSequentiallyConsistent()); } - return weak_globals_.SynchronizedGet(ref).Ptr(); + return weak_globals_.SynchronizedGet(ref); } bool JavaVMExt::IsWeakGlobalCleared(Thread* self, IndirectRef ref) { @@ -711,7 +711,7 @@ bool JavaVMExt::IsWeakGlobalCleared(Thread* self, IndirectRef ref) { return Runtime::Current()->IsClearedJniWeakGlobal(weak_globals_.Get<kWithoutReadBarrier>(ref)); } -void JavaVMExt::UpdateWeakGlobal(Thread* self, IndirectRef ref, mirror::Object* result) { +void JavaVMExt::UpdateWeakGlobal(Thread* self, IndirectRef ref, ObjPtr<mirror::Object> result) { MutexLock mu(self, weak_globals_lock_); weak_globals_.Update(ref, result); } diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h index 558ffffe5a..2e59a9d65f 100644 --- a/runtime/java_vm_ext.h +++ b/runtime/java_vm_ext.h @@ -137,23 +137,23 @@ class JavaVMExt : public JavaVM { void SweepJniWeakGlobals(IsMarkedVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!weak_globals_lock_); - mirror::Object* DecodeGlobal(IndirectRef ref) + ObjPtr<mirror::Object> DecodeGlobal(IndirectRef ref) REQUIRES_SHARED(Locks::mutator_lock_); - void UpdateGlobal(Thread* self, IndirectRef ref, mirror::Object* result) + void UpdateGlobal(Thread* self, IndirectRef ref, ObjPtr<mirror::Object> result) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!globals_lock_); - mirror::Object* DecodeWeakGlobal(Thread* self, IndirectRef ref) + ObjPtr<mirror::Object> DecodeWeakGlobal(Thread* self, IndirectRef ref) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!weak_globals_lock_); - mirror::Object* DecodeWeakGlobalLocked(Thread* self, IndirectRef ref) + ObjPtr<mirror::Object> DecodeWeakGlobalLocked(Thread* self, IndirectRef ref) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(weak_globals_lock_); // Like DecodeWeakGlobal() but to be used only during a runtime shutdown where self may be // null. - mirror::Object* DecodeWeakGlobalDuringShutdown(Thread* self, IndirectRef ref) + ObjPtr<mirror::Object> DecodeWeakGlobalDuringShutdown(Thread* self, IndirectRef ref) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!weak_globals_lock_); @@ -166,7 +166,7 @@ class JavaVMExt : public JavaVM { return weak_globals_lock_; } - void UpdateWeakGlobal(Thread* self, IndirectRef ref, mirror::Object* result) + void UpdateWeakGlobal(Thread* self, IndirectRef ref, ObjPtr<mirror::Object> result) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!weak_globals_lock_); const JNIInvokeInterface* GetUncheckedFunctions() const { diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc index dc3bf16a09..170887e397 100644 --- a/runtime/jdwp/object_registry.cc +++ b/runtime/jdwp/object_registry.cc @@ -180,7 +180,7 @@ mirror::Object* ObjectRegistry::InternalGet(JDWP::ObjectId id, JDWP::JdwpError* } ObjectRegistryEntry& entry = *it->second; *error = JDWP::ERR_NONE; - return self->DecodeJObject(entry.jni_reference); + return self->DecodeJObject(entry.jni_reference).Ptr(); } jobject ObjectRegistry::GetJObject(JDWP::ObjectId id) { diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc index 764458aece..1dd1e36e74 100644 --- a/runtime/jit/profile_compilation_info_test.cc +++ b/runtime/jit/profile_compilation_info_test.cc @@ -38,8 +38,8 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { Thread* self = Thread::Current(); ScopedObjectAccess soa(self); StackHandleScope<1> hs(self); - Handle<mirror::ClassLoader> h_loader(hs.NewHandle( - reinterpret_cast<mirror::ClassLoader*>(self->DecodeJObject(class_loader)))); + Handle<mirror::ClassLoader> h_loader( + hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader())); mirror::Class* klass = class_linker->FindClass(self, clazz.c_str(), h_loader); const auto pointer_size = class_linker->GetImagePointerSize(); diff --git a/runtime/jni_env_ext.cc b/runtime/jni_env_ext.cc index 0358494be8..3c749d0471 100644 --- a/runtime/jni_env_ext.cc +++ b/runtime/jni_env_ext.cc @@ -176,13 +176,13 @@ void JNIEnvExt::RecordMonitorEnter(jobject obj) { static std::string ComputeMonitorDescription(Thread* self, jobject obj) REQUIRES_SHARED(Locks::mutator_lock_) { - mirror::Object* o = self->DecodeJObject(obj); + ObjPtr<mirror::Object> o = self->DecodeJObject(obj); if ((o->GetLockWord(false).GetState() == LockWord::kThinLocked) && Locks::mutator_lock_->IsExclusiveHeld(self)) { // Getting the identity hashcode here would result in lock inflation and suspension of the // current thread, which isn't safe if this is the only runnable thread. return StringPrintf("<@addr=0x%" PRIxPTR "> (a %s)", - reinterpret_cast<intptr_t>(o), + reinterpret_cast<intptr_t>(o.Ptr()), PrettyTypeOf(o).c_str()); } else { // IdentityHashCode can cause thread suspension, which would invalidate o if it moved. So @@ -203,7 +203,7 @@ static void RemoveMonitors(Thread* self, [self, frame, monitors](const std::pair<uintptr_t, jobject>& pair) REQUIRES_SHARED(Locks::mutator_lock_) { if (frame == pair.first) { - mirror::Object* o = self->DecodeJObject(pair.second); + ObjPtr<mirror::Object> o = self->DecodeJObject(pair.second); monitors->Remove(o); return true; } @@ -221,7 +221,7 @@ void JNIEnvExt::CheckMonitorRelease(jobject obj) { locked_objects_.erase(it); } else { // Check whether this monitor was locked in another JNI "session." - mirror::Object* mirror_obj = self->DecodeJObject(obj); + ObjPtr<mirror::Object> mirror_obj = self->DecodeJObject(obj); for (std::pair<uintptr_t, jobject>& pair : locked_objects_) { if (self->DecodeJObject(pair.second) == mirror_obj) { std::string monitor_descr = ComputeMonitorDescription(self, pair.second); diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 621e2df313..f0a7c16146 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -528,7 +528,7 @@ class JNI { static jobject NewGlobalRef(JNIEnv* env, jobject obj) { ScopedObjectAccess soa(env); ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj); - return soa.Vm()->AddGlobalRef(soa.Self(), decoded_obj.Ptr()); + return soa.Vm()->AddGlobalRef(soa.Self(), decoded_obj); } static void DeleteGlobalRef(JNIEnv* env, jobject obj) { @@ -540,7 +540,7 @@ class JNI { static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) { ScopedObjectAccess soa(env); ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj); - return soa.Vm()->AddWeakGlobalRef(soa.Self(), decoded_obj.Ptr()); + return soa.Vm()->AddWeakGlobalRef(soa.Self(), decoded_obj); } static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) { @@ -2295,7 +2295,7 @@ class JNI { if (soa.Self()->IsExceptionPending()) { return JNI_ERR; } - soa.Env()->monitors.Add(o.Ptr()); + soa.Env()->monitors.Add(o); return JNI_OK; } @@ -2307,7 +2307,7 @@ class JNI { if (soa.Self()->IsExceptionPending()) { return JNI_ERR; } - soa.Env()->monitors.Remove(o.Ptr()); + soa.Env()->monitors.Remove(o); return JNI_OK; } diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 1cfed741eb..cc088b8aa8 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -448,7 +448,7 @@ inline bool Class::CanAccessResolvedField(ObjPtr<Class> access_to, inline bool Class::CheckResolvedFieldAccess(ObjPtr<Class> access_to, ArtField* field, uint32_t field_idx) { - return ResolvedFieldAccessTest<true, true>(access_to.Ptr(), field, field_idx, nullptr); + return ResolvedFieldAccessTest<true, true>(access_to, field, field_idx, nullptr); } inline bool Class::CanAccessResolvedMethod(Class* access_to, ArtMethod* method, diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 87bff5ffc5..2a5c04d54b 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -677,11 +677,10 @@ static jobject Class_newInstance(JNIEnv* env, jobject javaThis) { if (caller.Get() == nullptr) { caller.Assign(GetCallingClass(soa.Self(), 1)); } - if (UNLIKELY(caller.Get() != nullptr && !VerifyAccess( - MakeObjPtr(receiver.Get()), - MakeObjPtr(declaring_class), - constructor->GetAccessFlags(), - MakeObjPtr(caller.Get())))) { + if (UNLIKELY(caller.Get() != nullptr && !VerifyAccess(receiver.Get(), + declaring_class, + constructor->GetAccessFlags(), + caller.Get()))) { soa.Self()->ThrowNewExceptionF( "Ljava/lang/IllegalAccessException;", "%s is not accessible from %s", PrettyMethod(constructor).c_str(), PrettyClass(caller.Get()).c_str()); diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index 86b42d0051..90def4438f 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -46,8 +46,8 @@ ALWAYS_INLINE inline static bool VerifyFieldAccess(Thread* self, } ObjPtr<mirror::Class> calling_class; if (!VerifyAccess(self, - MakeObjPtr(obj), - MakeObjPtr(field->GetDeclaringClass()), + obj, + field->GetDeclaringClass(), field->GetAccessFlags(), &calling_class, 1)) { @@ -335,7 +335,7 @@ static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject j ObjPtr<mirror::Object> boxed_value = soa.Decode<mirror::Object>(javaValue); JValue unboxed_value; if (!UnboxPrimitiveForField(boxed_value, - MakeObjPtr(field_type), + field_type, f->GetArtField(), &unboxed_value)) { DCHECK(soa.Self()->IsExceptionPending()); diff --git a/runtime/obj_ptr.h b/runtime/obj_ptr.h index beb4d33a11..74be44eb23 100644 --- a/runtime/obj_ptr.h +++ b/runtime/obj_ptr.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_OBJ_PTR_H_ #include <ostream> +#include <type_traits> #include "base/mutex.h" // For Locks::mutator_lock_. #include "globals.h" @@ -45,14 +46,23 @@ class ObjPtr { template <typename Type> ALWAYS_INLINE ObjPtr(Type* ptr) REQUIRES_SHARED(Locks::mutator_lock_) - : reference_(Encode(static_cast<MirrorType*>(ptr))) {} + : reference_(Encode(static_cast<MirrorType*>(ptr))) { + static_assert(std::is_base_of<MirrorType, Type>::value, + "Input type must be a subtype of the ObjPtr type"); + } template <typename Type> - ALWAYS_INLINE ObjPtr(const ObjPtr<Type>& other) REQUIRES_SHARED(Locks::mutator_lock_) - : reference_(Encode(static_cast<MirrorType*>(other.Ptr()))) {} + ALWAYS_INLINE ObjPtr(const ObjPtr<Type, kPoison>& other) REQUIRES_SHARED(Locks::mutator_lock_) + : reference_(Encode(static_cast<MirrorType*>(other.Ptr()))) { + static_assert(std::is_base_of<MirrorType, Type>::value, + "Input type must be a subtype of the ObjPtr type"); + } template <typename Type> - ALWAYS_INLINE ObjPtr& operator=(const ObjPtr& other) { + ALWAYS_INLINE ObjPtr& operator=(const ObjPtr<Type, kPoison>& other) + REQUIRES_SHARED(Locks::mutator_lock_) { + static_assert(std::is_base_of<MirrorType, Type>::value, + "Input type must be a subtype of the ObjPtr type"); reference_ = Encode(static_cast<MirrorType*>(other.Ptr())); return *this; } @@ -122,6 +132,14 @@ class ObjPtr { } } + // Static function to be friendly with null pointers. + template <typename SourceType> + static ObjPtr<MirrorType> DownCast(ObjPtr<SourceType> ptr) REQUIRES_SHARED(Locks::mutator_lock_) { + static_assert(std::is_base_of<SourceType, MirrorType>::value, + "Target type must be a subtype of source type"); + return static_cast<MirrorType*>(ptr.Ptr()); + } + private: // Trim off high bits of thread local cookie. ALWAYS_INLINE static uintptr_t TrimCookie(uintptr_t cookie) { diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc index a1a23619f3..bea40c8781 100644 --- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc +++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc @@ -38,7 +38,11 @@ #include "art_jvmti.h" #include "jni_env_ext-inl.h" +#include "object_tagging.h" +#include "obj_ptr-inl.h" #include "runtime.h" +#include "scoped_thread_state_change-inl.h" +#include "thread_list.h" #include "transform.h" // TODO Remove this at some point by annotating all the methods. It was put in to make the skeleton @@ -47,6 +51,8 @@ namespace openjdkjvmti { +ObjectTagTable gObjectTagTable; + class JvmtiFunctions { private: static bool IsValidEnv(jvmtiEnv* env) { @@ -270,11 +276,42 @@ class JvmtiFunctions { } static jvmtiError GetTag(jvmtiEnv* env, jobject object, jlong* tag_ptr) { - return ERR(NOT_IMPLEMENTED); + if (object == nullptr || tag_ptr == nullptr) { + return ERR(NULL_POINTER); + } + + JNIEnv* jni_env = GetJniEnv(env); + if (jni_env == nullptr) { + return ERR(INTERNAL); + } + + art::ScopedObjectAccess soa(jni_env); + art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(object); + if (!gObjectTagTable.GetTag(obj.Ptr(), tag_ptr)) { + *tag_ptr = 0; + } + + return ERR(NONE); } static jvmtiError SetTag(jvmtiEnv* env, jobject object, jlong tag) { - return ERR(NOT_IMPLEMENTED); + if (object == nullptr) { + return ERR(NULL_POINTER); + } + + JNIEnv* jni_env = GetJniEnv(env); + if (jni_env == nullptr) { + return ERR(INTERNAL); + } + + art::ScopedObjectAccess soa(jni_env); + art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(object); + gObjectTagTable.Remove(obj.Ptr(), /* tag* */ nullptr); + if (tag != 0) { + gObjectTagTable.Add(obj.Ptr(), tag); + } + + return ERR(NONE); } static jvmtiError GetObjectsWithTags(jvmtiEnv* env, @@ -998,7 +1035,9 @@ static jint GetEnvHandler(art::JavaVMExt* vm, /*out*/void** env, jint version) { // The plugin initialization function. This adds the jvmti environment. extern "C" bool ArtPlugin_Initialize() { - art::Runtime::Current()->GetJavaVM()->AddEnvironmentHook(GetEnvHandler); + art::Runtime* runtime = art::Runtime::Current(); + runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler); + runtime->AddSystemWeakHolder(&gObjectTagTable); return true; } diff --git a/runtime/openjdkjvmti/object_tagging.h b/runtime/openjdkjvmti/object_tagging.h new file mode 100644 index 0000000000..523e15f6df --- /dev/null +++ b/runtime/openjdkjvmti/object_tagging.h @@ -0,0 +1,137 @@ +/* + * 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_RUNTIME_OPENJDKJVMTI_OBJECT_TAGGING_H_ +#define ART_RUNTIME_OPENJDKJVMTI_OBJECT_TAGGING_H_ + +#include "base/mutex.h" +#include "gc/system_weak.h" +#include "gc_root-inl.h" +#include "mirror/object.h" +#include "thread-inl.h" + +namespace openjdkjvmti { + +class ObjectTagTable : public art::gc::SystemWeakHolder { + public: + ObjectTagTable() : art::gc::SystemWeakHolder(art::LockLevel::kAllocTrackerLock) { + } + + void Add(art::mirror::Object* obj, jlong tag) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_) { + art::Thread* self = art::Thread::Current(); + art::MutexLock mu(self, allow_disallow_lock_); + Wait(self); + + if (first_free_ == tagged_objects_.size()) { + tagged_objects_.push_back(Entry(art::GcRoot<art::mirror::Object>(obj), tag)); + first_free_++; + } else { + DCHECK_LT(first_free_, tagged_objects_.size()); + DCHECK(tagged_objects_[first_free_].first.IsNull()); + tagged_objects_[first_free_] = Entry(art::GcRoot<art::mirror::Object>(obj), tag); + // TODO: scan for free elements. + first_free_ = tagged_objects_.size(); + } + } + + bool GetTag(art::mirror::Object* obj, jlong* result) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_) { + art::Thread* self = art::Thread::Current(); + art::MutexLock mu(self, allow_disallow_lock_); + Wait(self); + + for (const auto& pair : tagged_objects_) { + if (pair.first.Read(nullptr) == obj) { + *result = pair.second; + return true; + } + } + + return false; + } + + bool Remove(art::mirror::Object* obj, jlong* tag) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_) { + art::Thread* self = art::Thread::Current(); + art::MutexLock mu(self, allow_disallow_lock_); + Wait(self); + + for (auto it = tagged_objects_.begin(); it != tagged_objects_.end(); ++it) { + if (it->first.Read(nullptr) == obj) { + if (tag != nullptr) { + *tag = it->second; + } + it->first = art::GcRoot<art::mirror::Object>(nullptr); + + size_t index = it - tagged_objects_.begin(); + if (index < first_free_) { + first_free_ = index; + } + + // TODO: compaction. + + return true; + } + } + + return false; + } + + void Sweep(art::IsMarkedVisitor* visitor) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_) { + art::Thread* self = art::Thread::Current(); + art::MutexLock mu(self, allow_disallow_lock_); + + for (auto it = tagged_objects_.begin(); it != tagged_objects_.end(); ++it) { + if (!it->first.IsNull()) { + art::mirror::Object* original_obj = it->first.Read<art::kWithoutReadBarrier>(); + art::mirror::Object* target_obj = visitor->IsMarked(original_obj); + if (original_obj != target_obj) { + it->first = art::GcRoot<art::mirror::Object>(target_obj); + + if (target_obj == nullptr) { + HandleNullSweep(it->second); + } + } + } else { + size_t index = it - tagged_objects_.begin(); + if (index < first_free_) { + first_free_ = index; + } + } + } + } + + private: + using Entry = std::pair<art::GcRoot<art::mirror::Object>, jlong>; + + void HandleNullSweep(jlong tag ATTRIBUTE_UNUSED) { + // TODO: Handle deallocation reporting here. We'll have to enqueue tags temporarily, as we + // probably shouldn't call the callbacks directly (to avoid any issues). + } + + std::vector<Entry> tagged_objects_ GUARDED_BY(allow_disallow_lock_); + size_t first_free_ = 0; +}; + +} // namespace openjdkjvmti + +#endif // ART_RUNTIME_OPENJDKJVMTI_OBJECT_TAGGING_H_ diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc index f59e01e3db..3443aea744 100644 --- a/runtime/openjdkjvmti/transform.cc +++ b/runtime/openjdkjvmti/transform.cc @@ -327,8 +327,7 @@ jvmtiError MoveTransformedFileIntoRuntime(jclass jklass, class_linker->FindClass(self, dex_file_name, null_loader) ->FindDeclaredInstanceField("mInternalCookie", "Ljava/lang/Object;"); CHECK(dex_file_cookie_field != nullptr); - art::Handle<art::mirror::Class> klass( - hs.NewHandle(art::down_cast<art::mirror::Class*>(self->DecodeJObject(jklass)))); + art::Handle<art::mirror::Class> klass(hs.NewHandle(self->DecodeJObject(jklass)->AsClass())); art::mirror::Object* dex_file_ptr = nullptr; art::mirror::ClassLoader* class_loader_ptr = nullptr; // Find dalvik.system.DexFile that represents the dex file we are changing. diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index 1119ccfc80..84985c2997 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -180,7 +180,7 @@ TEST_F(ProxyTest, ProxyFieldHelper) { ArtField* field = &static_fields->At(0); EXPECT_STREQ("interfaces", field->GetName()); EXPECT_STREQ("[Ljava/lang/Class;", field->GetTypeDescriptor()); - EXPECT_OBJ_PTR_EQ(MakeObjPtr(interfacesFieldClass.Get()), field->GetType<true>()); + EXPECT_OBJ_PTR_EQ(interfacesFieldClass.Get(), field->GetType<true>()); std::string temp; EXPECT_STREQ("L$Proxy1234;", field->GetDeclaringClass()->GetDescriptor(&temp)); EXPECT_FALSE(field->IsPrimitiveType()); @@ -189,7 +189,7 @@ TEST_F(ProxyTest, ProxyFieldHelper) { field = &static_fields->At(1); EXPECT_STREQ("throws", field->GetName()); EXPECT_STREQ("[[Ljava/lang/Class;", field->GetTypeDescriptor()); - EXPECT_OBJ_PTR_EQ(MakeObjPtr(throwsFieldClass.Get()), field->GetType<true>()); + EXPECT_OBJ_PTR_EQ(throwsFieldClass.Get(), field->GetType<true>()); EXPECT_STREQ("L$Proxy1234;", field->GetDeclaringClass()->GetDescriptor(&temp)); EXPECT_FALSE(field->IsPrimitiveType()); } @@ -224,10 +224,10 @@ TEST_F(ProxyTest, CheckArtMirrorFieldsOfProxyStaticFields) { ASSERT_TRUE(static_fields1 != nullptr); ASSERT_EQ(2u, static_fields1->size()); - EXPECT_OBJ_PTR_EQ(static_fields0->At(0).GetDeclaringClass(), MakeObjPtr(proxyClass0.Get())); - EXPECT_OBJ_PTR_EQ(static_fields0->At(1).GetDeclaringClass(), MakeObjPtr(proxyClass0.Get())); - EXPECT_OBJ_PTR_EQ(static_fields1->At(0).GetDeclaringClass(), MakeObjPtr(proxyClass1.Get())); - EXPECT_OBJ_PTR_EQ(static_fields1->At(1).GetDeclaringClass(), MakeObjPtr(proxyClass1.Get())); + EXPECT_OBJ_PTR_EQ(static_fields0->At(0).GetDeclaringClass(), proxyClass0.Get()); + EXPECT_OBJ_PTR_EQ(static_fields0->At(1).GetDeclaringClass(), proxyClass0.Get()); + EXPECT_OBJ_PTR_EQ(static_fields1->At(0).GetDeclaringClass(), proxyClass1.Get()); + EXPECT_OBJ_PTR_EQ(static_fields1->At(1).GetDeclaringClass(), proxyClass1.Get()); ASSERT_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize); ASSERT_FALSE(Runtime::Current()->IsActiveTransaction()); diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc index 0be79efb76..e0ba8e7489 100644 --- a/runtime/reference_table.cc +++ b/runtime/reference_table.cc @@ -39,9 +39,9 @@ ReferenceTable::ReferenceTable(const char* name, size_t initial_size, size_t max ReferenceTable::~ReferenceTable() { } -void ReferenceTable::Add(mirror::Object* obj) { +void ReferenceTable::Add(ObjPtr<mirror::Object> obj) { DCHECK(obj != nullptr); - VerifyObject(obj); + VerifyObject(obj.Ptr()); if (entries_.size() >= max_size_) { LOG(FATAL) << "ReferenceTable '" << name_ << "' " << "overflowed (" << max_size_ << " entries)"; @@ -49,10 +49,10 @@ void ReferenceTable::Add(mirror::Object* obj) { entries_.push_back(GcRoot<mirror::Object>(obj)); } -void ReferenceTable::Remove(mirror::Object* obj) { +void ReferenceTable::Remove(ObjPtr<mirror::Object> obj) { // We iterate backwards on the assumption that references are LIFO. for (int i = entries_.size() - 1; i >= 0; --i) { - mirror::Object* entry = entries_[i].Read(); + ObjPtr<mirror::Object> entry = entries_[i].Read(); if (entry == obj) { entries_.erase(entries_.begin() + i); return; @@ -62,7 +62,7 @@ void ReferenceTable::Remove(mirror::Object* obj) { // If "obj" is an array, return the number of elements in the array. // Otherwise, return zero. -static size_t GetElementCount(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) { +static size_t GetElementCount(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_) { // We assume the special cleared value isn't an array in the if statement below. DCHECK(!Runtime::Current()->GetClearedJniWeakGlobal()->IsArrayInstance()); if (obj == nullptr || !obj->IsArrayInstance()) { @@ -76,7 +76,7 @@ static size_t GetElementCount(mirror::Object* obj) REQUIRES_SHARED(Locks::mutato // Pass in the number of elements in the array (or 0 if this is not an // array object), and the number of additional objects that are identical // or equivalent to the original. -static void DumpSummaryLine(std::ostream& os, mirror::Object* obj, size_t element_count, +static void DumpSummaryLine(std::ostream& os, ObjPtr<mirror::Object> obj, size_t element_count, int identical, int equiv) REQUIRES_SHARED(Locks::mutator_lock_) { if (obj == nullptr) { @@ -126,8 +126,8 @@ void ReferenceTable::Dump(std::ostream& os, Table& entries) { // are no suspend points which can happen during the sorting process. This works since // we are guaranteed that the addresses of obj1, obj2, obj1->GetClass, obj2->GetClass wont // change during the sorting process. The classes are forwarded by ref->GetClass(). - mirror::Object* obj1 = root1.Read<kWithoutReadBarrier>(); - mirror::Object* obj2 = root2.Read<kWithoutReadBarrier>(); + ObjPtr<mirror::Object> obj1 = root1.Read<kWithoutReadBarrier>(); + ObjPtr<mirror::Object> obj2 = root2.Read<kWithoutReadBarrier>(); DCHECK(obj1 != nullptr); DCHECK(obj2 != nullptr); Runtime* runtime = Runtime::Current(); @@ -144,7 +144,7 @@ void ReferenceTable::Dump(std::ostream& os, Table& entries) { return size1 < size2; } // ...and finally by address. - return obj1 < obj2; + return obj1.Ptr() < obj2.Ptr(); } }; @@ -163,7 +163,7 @@ void ReferenceTable::Dump(std::ostream& os, Table& entries) { os << " Last " << (count - first) << " entries (of " << count << "):\n"; Runtime* runtime = Runtime::Current(); for (int idx = count - 1; idx >= first; --idx) { - mirror::Object* ref = entries[idx].Read(); + ObjPtr<mirror::Object> ref = entries[idx].Read(); if (ref == nullptr) { continue; } @@ -174,7 +174,7 @@ void ReferenceTable::Dump(std::ostream& os, Table& entries) { if (ref->GetClass() == nullptr) { // should only be possible right after a plain dvmMalloc(). size_t size = ref->SizeOf(); - os << StringPrintf(" %5d: %p (raw) (%zd bytes)\n", idx, ref, size); + os << StringPrintf(" %5d: %p (raw) (%zd bytes)\n", idx, ref.Ptr(), size); continue; } @@ -185,7 +185,7 @@ void ReferenceTable::Dump(std::ostream& os, Table& entries) { if (element_count != 0) { StringAppendF(&extras, " (%zd elements)", element_count); } else if (ref->GetClass()->IsStringClass()) { - mirror::String* s = ref->AsString(); + ObjPtr<mirror::String> s = ref->AsString(); std::string utf8(s->ToModifiedUtf8()); if (s->GetLength() <= 16) { StringAppendF(&extras, " \"%s\"", utf8.c_str()); @@ -193,7 +193,7 @@ void ReferenceTable::Dump(std::ostream& os, Table& entries) { StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength()); } } else if (ref->IsReferenceInstance()) { - mirror::Object* referent = ref->AsReference()->GetReferent(); + ObjPtr<mirror::Object> referent = ref->AsReference()->GetReferent(); if (referent == nullptr) { extras = " (referent is null)"; } else { @@ -219,9 +219,9 @@ void ReferenceTable::Dump(std::ostream& os, Table& entries) { os << " Summary:\n"; size_t equiv = 0; size_t identical = 0; - mirror::Object* prev = nullptr; + ObjPtr<mirror::Object> prev = nullptr; for (GcRoot<mirror::Object>& root : sorted_entries) { - mirror::Object* current = root.Read<kWithoutReadBarrier>(); + ObjPtr<mirror::Object> current = root.Read<kWithoutReadBarrier>(); if (prev != nullptr) { const size_t element_count = GetElementCount(prev); if (current == prev) { diff --git a/runtime/reference_table.h b/runtime/reference_table.h index 992ded0eae..8423e04e88 100644 --- a/runtime/reference_table.h +++ b/runtime/reference_table.h @@ -25,6 +25,7 @@ #include "base/allocator.h" #include "base/mutex.h" #include "gc_root.h" +#include "obj_ptr.h" #include "object_callbacks.h" namespace art { @@ -41,9 +42,9 @@ class ReferenceTable { ReferenceTable(const char* name, size_t initial_size, size_t max_size); ~ReferenceTable(); - void Add(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_); + void Add(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_); - void Remove(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_); + void Remove(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_); size_t Size() const; diff --git a/runtime/reflection.cc b/runtime/reflection.cc index de003e525b..098eb0377a 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -676,8 +676,7 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaM } // Box if necessary and return. - return soa.AddLocalReference<jobject>( - BoxPrimitive(Primitive::GetType(shorty[0]), result).Ptr()); + return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result)); } ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value) { @@ -911,14 +910,14 @@ void UpdateReference(Thread* self, jobject obj, ObjPtr<mirror::Object> result) { IndirectRef ref = reinterpret_cast<IndirectRef>(obj); IndirectRefKind kind = GetIndirectRefKind(ref); if (kind == kLocal) { - self->GetJniEnv()->locals.Update(obj, result.Ptr()); + self->GetJniEnv()->locals.Update(obj, result); } else if (kind == kHandleScopeOrInvalid) { LOG(FATAL) << "Unsupported UpdateReference for kind kHandleScopeOrInvalid"; } else if (kind == kGlobal) { - self->GetJniEnv()->vm->UpdateGlobal(self, ref, result.Ptr()); + self->GetJniEnv()->vm->UpdateGlobal(self, ref, result); } else { DCHECK_EQ(kind, kWeakGlobal); - self->GetJniEnv()->vm->UpdateWeakGlobal(self, ref, result.Ptr()); + self->GetJniEnv()->vm->UpdateWeakGlobal(self, ref, result); } } diff --git a/runtime/scoped_thread_state_change-inl.h b/runtime/scoped_thread_state_change-inl.h index ac2575715e..1ebfd30ff7 100644 --- a/runtime/scoped_thread_state_change-inl.h +++ b/runtime/scoped_thread_state_change-inl.h @@ -83,7 +83,7 @@ template<typename T, bool kPoison> inline ObjPtr<T, kPoison> ScopedObjectAccessAlreadyRunnable::Decode(jobject obj) const { Locks::mutator_lock_->AssertSharedHeld(Self()); DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. - return down_cast<T*>(Self()->DecodeJObject(obj)); + return down_cast<T*>(Self()->DecodeJObject(obj).Ptr()); } inline ArtField* ScopedObjectAccessAlreadyRunnable::DecodeField(jfieldID fid) const { diff --git a/runtime/thread.cc b/runtime/thread.cc index 7335e409bf..3e2ecfe55e 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1856,7 +1856,7 @@ void Thread::HandleScopeVisitRoots(RootVisitor* visitor, uint32_t thread_id) { } } -mirror::Object* Thread::DecodeJObject(jobject obj) const { +ObjPtr<mirror::Object> Thread::DecodeJObject(jobject obj) const { if (obj == nullptr) { return nullptr; } @@ -1897,7 +1897,7 @@ mirror::Object* Thread::DecodeJObject(jobject obj) const { tlsPtr_.jni_env->vm->JniAbortF(nullptr, "use of deleted %s %p", ToStr<IndirectRefKind>(kind).c_str(), obj); } - return result.Ptr(); + return result; } bool Thread::IsJWeakCleared(jweak obj) const { @@ -2318,17 +2318,17 @@ void Thread::ThrowNewWrappedException(const char* exception_class_descriptor, // case in the compiler. We won't be able to invoke the constructor of the exception, so set // the exception fields directly. if (msg != nullptr) { - exception->SetDetailMessage(down_cast<mirror::String*>(DecodeJObject(msg_string.get()))); + exception->SetDetailMessage(DecodeJObject(msg_string.get())->AsString()); } if (cause.get() != nullptr) { - exception->SetCause(down_cast<mirror::Throwable*>(DecodeJObject(cause.get()))); + exception->SetCause(DecodeJObject(cause.get())->AsThrowable()); } ScopedLocalRef<jobject> trace(GetJniEnv(), Runtime::Current()->IsActiveTransaction() ? CreateInternalStackTrace<true>(soa) : CreateInternalStackTrace<false>(soa)); if (trace.get() != nullptr) { - exception->SetStackState(down_cast<mirror::Throwable*>(DecodeJObject(trace.get()))); + exception->SetStackState(DecodeJObject(trace.get()).Ptr()); } SetException(exception.Get()); } else { diff --git a/runtime/thread.h b/runtime/thread.h index 97053decc0..20b4cc144b 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -452,7 +452,7 @@ class Thread { } // Convert a jobject into a Object* - mirror::Object* DecodeJObject(jobject obj) const REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::Object> DecodeJObject(jobject obj) const REQUIRES_SHARED(Locks::mutator_lock_); // Checks if the weak global ref has been cleared by the GC without decoding it. bool IsJWeakCleared(jweak obj) const REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index f40f347c39..eba6666dec 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -61,7 +61,7 @@ static constexpr useconds_t kThreadSuspendMaxSleepUs = 5000; // Whether we should try to dump the native stack of unattached threads. See commit ed8b723 for // some history. // Turned off again. b/29248079 -static constexpr bool kDumpUnattachedThreadNativeStack = false; +static constexpr bool kDumpUnattachedThreadNativeStackForSigQuit = false; ThreadList::ThreadList() : suspend_all_count_(0), @@ -137,7 +137,7 @@ void ThreadList::DumpForSigQuit(std::ostream& os) { } bool dump_native_stack = Runtime::Current()->GetDumpNativeStackOnSigQuit(); Dump(os, dump_native_stack); - DumpUnattachedThreads(os, dump_native_stack); + DumpUnattachedThreads(os, dump_native_stack && kDumpUnattachedThreadNativeStackForSigQuit); } static void DumpUnattachedThread(std::ostream& os, pid_t tid, bool dump_native_stack) @@ -146,7 +146,7 @@ static void DumpUnattachedThread(std::ostream& os, pid_t tid, bool dump_native_s // refactor DumpState to avoid skipping analysis. Thread::DumpState(os, nullptr, tid); DumpKernelStack(os, tid, " kernel: ", false); - if (dump_native_stack && kDumpUnattachedThreadNativeStack) { + if (dump_native_stack) { DumpNativeStack(os, tid, nullptr, " native: "); } os << "\n"; @@ -194,6 +194,7 @@ class DumpCheckpoint FINAL : public Closure { // Note thread and self may not be equal if thread was already suspended at the point of the // request. Thread* self = Thread::Current(); + CHECK(self != nullptr); std::ostringstream local_os; { ScopedObjectAccess soa(self); @@ -231,19 +232,24 @@ class DumpCheckpoint FINAL : public Closure { }; void ThreadList::Dump(std::ostream& os, bool dump_native_stack) { + Thread* self = Thread::Current(); { - MutexLock mu(Thread::Current(), *Locks::thread_list_lock_); + MutexLock mu(self, *Locks::thread_list_lock_); os << "DALVIK THREADS (" << list_.size() << "):\n"; } - DumpCheckpoint checkpoint(&os, dump_native_stack); - size_t threads_running_checkpoint; - { - // Use SOA to prevent deadlocks if multiple threads are calling Dump() at the same time. - ScopedObjectAccess soa(Thread::Current()); - threads_running_checkpoint = RunCheckpoint(&checkpoint); - } - if (threads_running_checkpoint != 0) { - checkpoint.WaitForThreadsToRunThroughCheckpoint(threads_running_checkpoint); + if (self != nullptr) { + DumpCheckpoint checkpoint(&os, dump_native_stack); + size_t threads_running_checkpoint; + { + // Use SOA to prevent deadlocks if multiple threads are calling Dump() at the same time. + ScopedObjectAccess soa(self); + threads_running_checkpoint = RunCheckpoint(&checkpoint); + } + if (threads_running_checkpoint != 0) { + checkpoint.WaitForThreadsToRunThroughCheckpoint(threads_running_checkpoint); + } + } else { + DumpUnattachedThreads(os, dump_native_stack); } } diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 4dcf58fc93..78fc53ac36 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -24,6 +24,7 @@ #include "entrypoints/quick/quick_entrypoints_enum.h" #include "mirror/class.h" #include "mirror/throwable.h" +#include "obj_ptr-inl.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" @@ -385,8 +386,8 @@ void WellKnownClasses::LateInit(JNIEnv* env) { "Ljava/lang/String;"); } -mirror::Class* WellKnownClasses::ToClass(jclass global_jclass) { - return reinterpret_cast<mirror::Class*>(Thread::Current()->DecodeJObject(global_jclass)); +ObjPtr<mirror::Class> WellKnownClasses::ToClass(jclass global_jclass) { + return ObjPtr<mirror::Class>::DownCast(Thread::Current()->DecodeJObject(global_jclass)); } } // namespace art diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index ddfc5b80f7..248ba7f431 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -19,6 +19,7 @@ #include "base/mutex.h" #include "jni.h" +#include "obj_ptr.h" namespace art { @@ -41,8 +42,7 @@ struct WellKnownClasses { static ArtMethod* StringInitToStringFactory(ArtMethod* method); static uint32_t StringInitToEntryPoint(ArtMethod* method); - static mirror::Class* ToClass(jclass global_jclass) - REQUIRES_SHARED(Locks::mutator_lock_); + static ObjPtr<mirror::Class> ToClass(jclass global_jclass) REQUIRES_SHARED(Locks::mutator_lock_); static jclass com_android_dex_Dex; static jclass dalvik_annotation_optimization_CriticalNative; diff --git a/test/903-hello-tagging/build b/test/903-hello-tagging/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/903-hello-tagging/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/903-hello-tagging/expected.txt b/test/903-hello-tagging/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/903-hello-tagging/expected.txt diff --git a/test/903-hello-tagging/info.txt b/test/903-hello-tagging/info.txt new file mode 100644 index 0000000000..875a5f6ec1 --- /dev/null +++ b/test/903-hello-tagging/info.txt @@ -0,0 +1 @@ +Tests basic functions in the jvmti plugin. diff --git a/test/903-hello-tagging/run b/test/903-hello-tagging/run new file mode 100755 index 0000000000..5e3c0bd32a --- /dev/null +++ b/test/903-hello-tagging/run @@ -0,0 +1,43 @@ +#!/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. + +plugin=libopenjdkjvmtid.so +agent=libtiagentd.so +lib=tiagentd +if [[ "$@" == *"-O"* ]]; then + agent=libtiagent.so + plugin=libopenjdkjvmti.so + lib=tiagent +fi + +if [[ "$@" == *"--jvm"* ]]; then + arg="jvm" +else + arg="art" +fi + +if [[ "$@" != *"--debuggable"* ]]; then + other_args=" -Xcompiler-option --debuggable " +else + other_args="" +fi + +./default-run "$@" --experimental agents \ + --experimental runtime-plugins \ + --runtime-option -agentpath:${agent}=903-hello-tagging,${arg} \ + --android-runtime-option -Xplugin:${plugin} \ + ${other_args} \ + --args ${lib} diff --git a/test/903-hello-tagging/src/Main.java b/test/903-hello-tagging/src/Main.java new file mode 100644 index 0000000000..2856a398c9 --- /dev/null +++ b/test/903-hello-tagging/src/Main.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +import java.lang.ref.WeakReference; + +public class Main { + public static void main(String[] args) { + System.loadLibrary(args[1]); + doTest(); + } + + public static void doTest() { + WeakReference<Object> weak = test(); + + Runtime.getRuntime().gc(); + Runtime.getRuntime().gc(); + + if (weak.get() != null) { + throw new RuntimeException("WeakReference not cleared"); + } + } + + private static WeakReference<Object> test() { + Object o1 = new Object(); + setTag(o1, 1); + + Object o2 = new Object(); + setTag(o2, 2); + + checkTag(o1, 1); + checkTag(o2, 2); + + Runtime.getRuntime().gc(); + Runtime.getRuntime().gc(); + + checkTag(o1, 1); + checkTag(o2, 2); + + Runtime.getRuntime().gc(); + Runtime.getRuntime().gc(); + + setTag(o1, 10); + setTag(o2, 20); + + checkTag(o1, 10); + checkTag(o2, 20); + + return new WeakReference<Object>(o1); + } + + private static void checkTag(Object o, long expectedTag) { + long tag = getTag(o); + if (expectedTag != tag) { + throw new RuntimeException("Unexpected tag " + tag + ", expected " + expectedTag); + } + } + + private static native void setTag(Object o, long tag); + private static native long getTag(Object o); +} diff --git a/test/903-hello-tagging/tagging.cc b/test/903-hello-tagging/tagging.cc new file mode 100644 index 0000000000..8ccdf49892 --- /dev/null +++ b/test/903-hello-tagging/tagging.cc @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 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 "tagging.h" + +#include <iostream> +#include <pthread.h> +#include <stdio.h> +#include <vector> + +#include "art_method-inl.h" +#include "base/logging.h" +#include "jni.h" +#include "openjdkjvmti/jvmti.h" +#include "utils.h" + +namespace art { +namespace Test903HelloTagging { + +static jvmtiEnv* jvmti_env; + +extern "C" JNIEXPORT void JNICALL Java_Main_setTag(JNIEnv* env ATTRIBUTE_UNUSED, + jclass, + jobject obj, + jlong tag) { + jvmtiError ret = jvmti_env->SetTag(obj, tag); + if (ret != JVMTI_ERROR_NONE) { + char* err; + jvmti_env->GetErrorName(ret, &err); + printf("Error setting tag: %s\n", err); + } +} + +extern "C" JNIEXPORT jlong JNICALL Java_Main_getTag(JNIEnv* env ATTRIBUTE_UNUSED, + jclass, + jobject obj) { + jlong tag = 0; + jvmtiError ret = jvmti_env->GetTag(obj, &tag); + if (ret != JVMTI_ERROR_NONE) { + char* err; + jvmti_env->GetErrorName(ret, &err); + printf("Error getting tag: %s\n", err); + } + return tag; +} + +// 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; + } + return 0; +} + +} // namespace Test903HelloTagging +} // namespace art + diff --git a/test/903-hello-tagging/tagging.h b/test/903-hello-tagging/tagging.h new file mode 100644 index 0000000000..f062d44880 --- /dev/null +++ b/test/903-hello-tagging/tagging.h @@ -0,0 +1,30 @@ +/* + * 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/Android.bp b/test/Android.bp index 628f3772e0..d17261cd68 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -245,6 +245,7 @@ art_cc_test_library { "ti-agent/common_load.cc", "901-hello-ti-agent/basics.cc", "902-hello-transformation/transform.cc", + "903-hello-tagging/tagging.cc", ], shared_libs: [ "libart", @@ -263,9 +264,11 @@ art_cc_test_library { "ti-agent/common_load.cc", "901-hello-ti-agent/basics.cc", "902-hello-transformation/transform.cc", + "903-hello-tagging/tagging.cc", ], shared_libs: [ "libartd", + "libbase", "libopenjdkjvmtid", ], } diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 064fb25306..a858c75fc2 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -263,12 +263,14 @@ endif # 147-stripped-dex-fallback isn't supported on device because --strip-dex # requires the zip command. # 569-checker-pattern-replacement tests behaviour present only on host. -# 902-hello-transformation isn't supported in current form due to linker +# 902-hello-transformation and 903-hello-tagging +# isn't supported in current form due to linker # restrictions. See b/31681198 TEST_ART_BROKEN_TARGET_TESTS := \ 147-stripped-dex-fallback \ 569-checker-pattern-replacement \ - 902-hello-transformation + 902-hello-transformation \ + 903-hello-tagging ifneq (,$(filter target,$(TARGET_TYPES))) ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \ diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc index 53bb1533e7..4c7df97374 100644 --- a/test/ti-agent/common_load.cc +++ b/test/ti-agent/common_load.cc @@ -25,6 +25,7 @@ #include "901-hello-ti-agent/basics.h" #include "902-hello-transformation/transform.h" +#include "903-hello-tagging/tagging.h" namespace art { @@ -41,6 +42,7 @@ struct AgentLib { AgentLib agents[] = { { "901-hello-ti-agent", Test901HelloTi::OnLoad, nullptr }, { "902-hello-transformation", Test902HelloTransformation::OnLoad, nullptr }, + { "903-hello-tagging", Test903HelloTagging::OnLoad, nullptr }, }; static AgentLib* FindAgent(char* name) { |