12faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes/* 22faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Copyright (C) 2011 The Android Open Source Project 32faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * 42faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License"); 52faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * you may not use this file except in compliance with the License. 62faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * You may obtain a copy of the License at 72faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * 82faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 92faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * 102faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Unless required by applicable law or agreed to in writing, software 112faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 122faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * See the License for the specific language governing permissions and 142faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * limitations under the License. 152faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes */ 1611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes 1711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes#include "reference_table.h" 1811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes 195573c37e795668eca81a8488078f798d977685c3Igor Murashkin#include <regex> 208a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe 2146ee31b67d7ee1bd085fbc240502053caa3cf8faAndreas Gampe#include "android-base/stringprintf.h" 2246ee31b67d7ee1bd085fbc240502053caa3cf8faAndreas Gampe 23c6ea7d00ad069a2736f603daa3d8eaa9a1f8ea11Andreas Gampe#include "art_method-inl.h" 24a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe#include "class_linker.h" 25a1ce1fef2d49d1d537776a5308ace7102a815fe5Brian Carlstrom#include "common_runtime_test.h" 2667bf42e89592c3a1c648f927f2ce3ccb189a1161David Sehr#include "dex/primitive.h" 27a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe#include "handle_scope-inl.h" 288db4c882a8d1996852163ebec966c8b4eb1e00dfAndreas Gampe#include "mirror/array-inl.h" 29e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier#include "mirror/class-inl.h" 30a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe#include "mirror/class_loader.h" 31e63db27db913f1a88e2095a1ee8239b2bb9124e8Ian Rogers#include "mirror/string.h" 32a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe#include "runtime.h" 330795f23920ee9aabf28e45c63cd592dcccf00216Mathieu Chartier#include "scoped_thread_state_change-inl.h" 34b486a98aadc95d80548953410cf23edba62259faAndreas Gampe#include "thread-current-inl.h" 358a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe#include "well_known_classes.h" 36a1ce1fef2d49d1d537776a5308ace7102a815fe5Brian Carlstrom 3711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughesnamespace art { 3811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes 3946ee31b67d7ee1bd085fbc240502053caa3cf8faAndreas Gampeusing android::base::StringPrintf; 4046ee31b67d7ee1bd085fbc240502053caa3cf8faAndreas Gampe 41a1ce1fef2d49d1d537776a5308ace7102a815fe5Brian Carlstromclass ReferenceTableTest : public CommonRuntimeTest {}; 4211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes 43a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampestatic mirror::Object* CreateWeakReference(mirror::Object* referent) 44a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe REQUIRES_SHARED(Locks::mutator_lock_) { 45a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe Thread* self = Thread::Current(); 46a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 47a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe 48a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe StackHandleScope<3> scope(self); 49a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe Handle<mirror::Object> h_referent(scope.NewHandle<mirror::Object>(referent)); 50a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe 51a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe Handle<mirror::Class> h_ref_class(scope.NewHandle<mirror::Class>( 52a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe class_linker->FindClass(self, 53a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe "Ljava/lang/ref/WeakReference;", 54a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe ScopedNullHandle<mirror::ClassLoader>()))); 55fa4333dcb481e564f54726b4e6f8153612df835eAndreas Gampe CHECK(h_ref_class != nullptr); 56a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe CHECK(class_linker->EnsureInitialized(self, h_ref_class, true, true)); 57a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe 58a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe Handle<mirror::Object> h_ref_instance(scope.NewHandle<mirror::Object>( 59a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe h_ref_class->AllocObject(self))); 60fa4333dcb481e564f54726b4e6f8153612df835eAndreas Gampe CHECK(h_ref_instance != nullptr); 61a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe 62ba118827465d12177f3996e50133960087b1c916Vladimir Marko ArtMethod* constructor = h_ref_class->FindConstructor( 63ba118827465d12177f3996e50133960087b1c916Vladimir Marko "(Ljava/lang/Object;)V", class_linker->GetImagePointerSize()); 64a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe CHECK(constructor != nullptr); 65a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe 66a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe uint32_t args[2]; 67a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe args[0] = PointerToLowMemUInt32(h_ref_instance.Get()); 68a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe args[1] = PointerToLowMemUInt32(h_referent.Get()); 69a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe JValue result; 70a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe constructor->Invoke(self, args, sizeof(uint32_t), &result, constructor->GetShorty()); 71a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe CHECK(!self->IsExceptionPending()); 72a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe 73a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe return h_ref_instance.Get(); 74a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe} 75a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe 7611e45077acba2e757799a00b3be9d63fec36a7ccElliott HughesTEST_F(ReferenceTableTest, Basics) { 7700f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers ScopedObjectAccess soa(Thread::Current()); 782dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers mirror::Object* o1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello"); 7911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes 8063818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers ReferenceTable rt("test", 0, 11); 8163818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers 8263818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers // Check dumping the empty table. 8363818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers { 8463818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers std::ostringstream oss; 8563818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers rt.Dump(oss); 8663818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_NE(oss.str().find("(empty)"), std::string::npos) << oss.str(); 8763818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_EQ(0U, rt.Size()); 8863818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } 8963818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers 902cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier // Check removal of all nullss in a empty table is a no-op. 912cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier rt.Remove(nullptr); 9211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes EXPECT_EQ(0U, rt.Size()); 9363818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers 9463818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers // Check removal of all o1 in a empty table is a no-op. 9511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes rt.Remove(o1); 9611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes EXPECT_EQ(0U, rt.Size()); 9763818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers 9863818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers // Add o1 and check we have 1 element and can dump. 9963818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers { 10063818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers rt.Add(o1); 10163818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_EQ(1U, rt.Size()); 10263818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers std::ostringstream oss; 10363818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers rt.Dump(oss); 10463818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_NE(oss.str().find("1 of java.lang.String"), std::string::npos) << oss.str(); 10563818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_EQ(oss.str().find("short[]"), std::string::npos) << oss.str(); 10663818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } 10763818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers 10863818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers // Add a second object 10 times and check dumping is sane. 1092dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers mirror::Object* o2 = mirror::ShortArray::Alloc(soa.Self(), 0); 11063818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers for (size_t i = 0; i < 10; ++i) { 11163818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers rt.Add(o2); 11263818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_EQ(i + 2, rt.Size()); 11363818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers std::ostringstream oss; 11463818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers rt.Dump(oss); 11563818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_NE(oss.str().find(StringPrintf("Last %zd entries (of %zd):", 11663818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers i + 2 > 10 ? 10 : i + 2, 11763818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers i + 2)), 11863818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers std::string::npos) << oss.str(); 11963818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_NE(oss.str().find("1 of java.lang.String"), std::string::npos) << oss.str(); 12063818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers if (i == 0) { 12163818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_NE(oss.str().find("1 of short[]"), std::string::npos) << oss.str(); 12263818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } else { 12363818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_NE(oss.str().find(StringPrintf("%zd of short[] (1 unique instances)", i + 1)), 12463818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers std::string::npos) << oss.str(); 12563818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } 12663818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } 12763818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers 12863818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers // Remove o1 (first element). 12963818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers { 13063818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers rt.Remove(o1); 13163818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_EQ(10U, rt.Size()); 13263818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers std::ostringstream oss; 13363818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers rt.Dump(oss); 13463818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_EQ(oss.str().find("java.lang.String"), std::string::npos) << oss.str(); 13563818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } 13663818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers 13763818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers // Remove o2 ten times. 13863818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers for (size_t i = 0; i < 10; ++i) { 13963818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers rt.Remove(o2); 14063818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_EQ(9 - i, rt.Size()); 14163818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers std::ostringstream oss; 14263818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers rt.Dump(oss); 14363818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers if (i == 9) { 14463818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_EQ(oss.str().find("short[]"), std::string::npos) << oss.str(); 14563818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } else if (i == 8) { 14663818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_NE(oss.str().find("1 of short[]"), std::string::npos) << oss.str(); 14763818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } else { 14863818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers EXPECT_NE(oss.str().find(StringPrintf("%zd of short[] (1 unique instances)", 10 - i - 1)), 14963818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers std::string::npos) << oss.str(); 15063818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } 15163818dc8b06af4a1e65c41b453f1a42166c22728Ian Rogers } 152a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe 153a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe // Add a reference and check that the type of the referent is dumped. 154a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe { 155a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe mirror::Object* empty_reference = CreateWeakReference(nullptr); 156a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe ASSERT_TRUE(empty_reference->IsReferenceInstance()); 157a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe rt.Add(empty_reference); 158a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe std::ostringstream oss; 159a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe rt.Dump(oss); 160a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is null)"), std::string::npos) 161a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe << oss.str(); 1628a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe rt.Remove(empty_reference); 163a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe } 164a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe 165a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe { 166a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe mirror::Object* string_referent = mirror::String::AllocFromModifiedUtf8(Thread::Current(), "A"); 167a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe mirror::Object* non_empty_reference = CreateWeakReference(string_referent); 168a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe ASSERT_TRUE(non_empty_reference->IsReferenceInstance()); 169a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe rt.Add(non_empty_reference); 170a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe std::ostringstream oss; 171a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe rt.Dump(oss); 172a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is a java.lang.String)"), 173a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe std::string::npos) 174a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe << oss.str(); 1758a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe rt.Remove(non_empty_reference); 1768a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe } 1778a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe 1788a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe // Add two objects. Enable allocation tracking for the latter. 1798a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe { 1808a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe StackHandleScope<3> hs(soa.Self()); 1818a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe Handle<mirror::String> h_without_trace(hs.NewHandle( 1828a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe mirror::String::AllocFromModifiedUtf8(soa.Self(), "Without"))); 1838a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe 1848a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe { 1858a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe ScopedThreadSuspension sts(soa.Self(), ThreadState::kSuspended); 1868a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe gc::AllocRecordObjectMap::SetAllocTrackingEnabled(true); 1878a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe } 1888a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe 1898a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe // To get a stack, actually make a call. Use substring, that's simple. Calling through JNI 1908a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe // avoids having to create the low-level args array ourselves. 1918a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe Handle<mirror::Object> h_with_trace; 1928a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe { 1938a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe jmethodID substr = soa.Env()->GetMethodID(WellKnownClasses::java_lang_String, 1948a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe "substring", 1958a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe "(II)Ljava/lang/String;"); 1968a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe ASSERT_TRUE(substr != nullptr); 1978a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe jobject jobj = soa.Env()->AddLocalReference<jobject>(h_without_trace.Get()); 1988a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe ASSERT_TRUE(jobj != nullptr); 1998a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe jobject result = soa.Env()->CallObjectMethod(jobj, 2008a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe substr, 2018a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe static_cast<jint>(0), 2028a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe static_cast<jint>(4)); 2038a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe ASSERT_TRUE(result != nullptr); 2048a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe h_with_trace = hs.NewHandle(soa.Self()->DecodeJObject(result)); 2058a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe } 2068a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe 2078a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe Handle<mirror::Object> h_ref; 2088a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe { 2098a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe jclass weak_ref_class = soa.Env()->FindClass("java/lang/ref/WeakReference"); 2108a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe ASSERT_TRUE(weak_ref_class != nullptr); 2118a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe jmethodID init = soa.Env()->GetMethodID(weak_ref_class, 2128a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe "<init>", 2138a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe "(Ljava/lang/Object;)V"); 2148a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe ASSERT_TRUE(init != nullptr); 2158a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe jobject referent = soa.Env()->AddLocalReference<jobject>(h_with_trace.Get()); 2168a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe jobject result = soa.Env()->NewObject(weak_ref_class, init, referent); 2178a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe ASSERT_TRUE(result != nullptr); 2188a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe h_ref = hs.NewHandle(soa.Self()->DecodeJObject(result)); 2198a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe } 2208a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe 2218a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe rt.Add(h_without_trace.Get()); 2228a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe rt.Add(h_with_trace.Get()); 2238a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe rt.Add(h_ref.Get()); 2248a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe 2258a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe std::ostringstream oss; 2268a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe rt.Dump(oss); 2278a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe 2288a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe constexpr const char* kStackTracePattern = 2298a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"(test reference table dump:\n)" 2308a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( Last 3 entries \(of 3\):\n)" // NOLINT 2318a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( 2: 0x[0-9a-f]* java.lang.ref.WeakReference \(referent is a java.lang.String\)\n)" // NOLINT 2328a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( Allocated at:\n)" 2338a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( \(No managed frames\)\n)" // NOLINT 2348a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( Referent allocated at:\n)" 2358a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( java.lang.String java.lang.String.fastSubstring\(int, int\):-2\n)" // NOLINT 2368a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( java.lang.String java.lang.String.substring\(int, int\):[0-9]*\n)" // NOLINT 2378a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( 1: 0x[0-9a-f]* java.lang.String "With"\n)" 2388a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( Allocated at:\n)" 2398a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( java.lang.String java.lang.String.fastSubstring\(int, int\):-2\n)" // NOLINT 2408a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( java.lang.String java.lang.String.substring\(int, int\):[0-9]*\n)" // NOLINT 2418a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( 0: 0x[0-9a-f]* java.lang.String "Without"\n)" 2428a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( Summary:\n)" 2438a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( 2 of java.lang.String \(2 unique instances\)\n)" // NOLINT 2448a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe R"( 1 of java.lang.ref.WeakReference\n)"; 2458a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe std::regex stack_trace_regex(kStackTracePattern); 2468a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe std::smatch stack_trace_match; 2478a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe std::string str = oss.str(); 2488a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe bool found = std::regex_search(str, stack_trace_match, stack_trace_regex); 2498a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe EXPECT_TRUE(found) << str; 2508a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe 2518a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe { 2528a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe ScopedThreadSuspension sts(soa.Self(), ThreadState::kSuspended); 2538a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe gc::AllocRecordObjectMap::SetAllocTrackingEnabled(false); 2548a2a1fc5d7a338a9b29794b2ee5b40a1c24a4e52Andreas Gampe } 255a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08bAndreas Gampe } 25611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes} 25711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes 2586e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampestatic std::vector<size_t> FindAll(const std::string& haystack, const char* needle) { 2596e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe std::vector<size_t> res; 2606e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe size_t start = 0; 2616e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe do { 2626e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe size_t pos = haystack.find(needle, start); 2636e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe if (pos == std::string::npos) { 2646e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe break; 2656e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe } 2666e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe res.push_back(pos); 2676e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe start = pos + 1; 2686e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe } while (start < haystack.size()); 2696e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe return res; 2706e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe} 2716e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 2726e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas GampeTEST_F(ReferenceTableTest, SummaryOrder) { 2736e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe // Check that the summary statistics are sorted. 2746e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe ScopedObjectAccess soa(Thread::Current()); 2756e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 2766e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe ReferenceTable rt("test", 0, 20); 2776e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 2786e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe { 2796e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe mirror::Object* s1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello"); 2806e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe mirror::Object* s2 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "world"); 2816e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 2826e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe // 3 copies of s1, 2 copies of s2, interleaved. 2836e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe for (size_t i = 0; i != 2; ++i) { 2846e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Add(s1); 2856e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Add(s2); 2866e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe } 2876e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Add(s1); 2886e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe } 2896e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 2906e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe { 2916e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe // Differently sized byte arrays. Should be sorted by identical (non-unique cound). 2926e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe mirror::Object* b1_1 = mirror::ByteArray::Alloc(soa.Self(), 1); 2936e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Add(b1_1); 2946e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2)); 2956e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Add(b1_1); 2966e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2)); 2976e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Add(mirror::ByteArray::Alloc(soa.Self(), 1)); 2986e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2)); 2996e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe } 3006e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 3016e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Add(mirror::CharArray::Alloc(soa.Self(), 0)); 3026e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 3036e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe // Now dump, and ensure order. 3046e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe std::ostringstream oss; 3056e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe rt.Dump(oss); 3066e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 3076e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe // Only do this on the part after Summary. 3086e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe std::string base = oss.str(); 3096e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe size_t summary_pos = base.find("Summary:"); 3106e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe ASSERT_NE(summary_pos, std::string::npos); 3116e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 3126e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe std::string haystack = base.substr(summary_pos); 3136e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 3146e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe std::vector<size_t> strCounts = FindAll(haystack, "java.lang.String"); 3156e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe std::vector<size_t> b1Counts = FindAll(haystack, "byte[] (1 elements)"); 3166e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe std::vector<size_t> b2Counts = FindAll(haystack, "byte[] (2 elements)"); 3176e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe std::vector<size_t> cCounts = FindAll(haystack, "char[]"); 3186e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 3196e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe // Only one each. 3206e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe EXPECT_EQ(1u, strCounts.size()); 3216e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe EXPECT_EQ(1u, b1Counts.size()); 3226e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe EXPECT_EQ(1u, b2Counts.size()); 3236e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe EXPECT_EQ(1u, cCounts.size()); 3246e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 3256e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe // Expect them to be in order. 3266e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe EXPECT_LT(strCounts[0], b1Counts[0]); 3276e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe EXPECT_LT(b1Counts[0], b2Counts[0]); 3286e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe EXPECT_LT(b2Counts[0], cCounts[0]); 3296e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe} 3306e970e7fa88efd5ee38b0d6f9010a3985c62778fAndreas Gampe 33111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes} // namespace art 332