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