summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/driver/compiler_driver_test.cc8
-rw-r--r--compiler/image_writer.cc43
-rw-r--r--compiler/image_writer.h4
-rw-r--r--compiler/jni/jni_compiler_test.cc5
-rw-r--r--oatdump/oatdump.cc6
-rw-r--r--runtime/check_jni.cc2
-rw-r--r--runtime/class_linker-inl.h5
-rw-r--r--runtime/class_linker.cc39
-rw-r--r--runtime/class_linker_test.cc4
-rw-r--r--runtime/common_throws.cc2
-rw-r--r--runtime/debugger.cc2
-rw-r--r--runtime/dex_file_annotations.cc2
-rw-r--r--runtime/entrypoints/quick/quick_jni_entrypoints.cc11
-rw-r--r--runtime/gc/collector/concurrent_copying.cc7
-rw-r--r--runtime/gc/space/space_test.h2
-rw-r--r--runtime/interpreter/unstarted_runtime.cc8
-rw-r--r--runtime/java_vm_ext.cc24
-rw-r--r--runtime/java_vm_ext.h12
-rw-r--r--runtime/jdwp/object_registry.cc2
-rw-r--r--runtime/jit/profile_compilation_info_test.cc4
-rw-r--r--runtime/jni_env_ext.cc8
-rw-r--r--runtime/jni_internal.cc8
-rw-r--r--runtime/mirror/class-inl.h2
-rw-r--r--runtime/native/java_lang_Class.cc9
-rw-r--r--runtime/native/java_lang_reflect_Field.cc6
-rw-r--r--runtime/obj_ptr.h26
-rw-r--r--runtime/openjdkjvmti/OpenjdkJvmTi.cc45
-rw-r--r--runtime/openjdkjvmti/object_tagging.h137
-rw-r--r--runtime/openjdkjvmti/transform.cc3
-rw-r--r--runtime/proxy_test.cc12
-rw-r--r--runtime/reference_table.cc30
-rw-r--r--runtime/reference_table.h5
-rw-r--r--runtime/reflection.cc9
-rw-r--r--runtime/scoped_thread_state_change-inl.h2
-rw-r--r--runtime/thread.cc10
-rw-r--r--runtime/thread.h2
-rw-r--r--runtime/thread_list.cc32
-rw-r--r--runtime/well_known_classes.cc5
-rw-r--r--runtime/well_known_classes.h4
-rwxr-xr-xtest/903-hello-tagging/build17
-rw-r--r--test/903-hello-tagging/expected.txt0
-rw-r--r--test/903-hello-tagging/info.txt1
-rwxr-xr-xtest/903-hello-tagging/run43
-rw-r--r--test/903-hello-tagging/src/Main.java73
-rw-r--r--test/903-hello-tagging/tagging.cc73
-rw-r--r--test/903-hello-tagging/tagging.h30
-rw-r--r--test/Android.bp3
-rw-r--r--test/Android.run-test.mk6
-rw-r--r--test/ti-agent/common_load.cc2
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) {