blob: 367da99320c6b3563b12415272593abb774b5524 [file] [log] [blame]
Andreas Gampecc13b222016-10-10 19:09:09 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Andreas Gampe46651672017-04-07 09:00:04 -070017package art;
18
Alex Light22d8e482018-07-26 16:06:15 -070019import java.lang.ref.PhantomReference;
20import java.lang.ref.ReferenceQueue;
Andreas Gampecc13b222016-10-10 19:09:09 -070021import java.util.ArrayList;
Andreas Gampee54eee12016-10-20 19:03:58 -070022import java.util.Arrays;
Alex Light35a760d2019-02-12 14:24:38 -080023import java.util.function.BiConsumer;
Andreas Gampecc13b222016-10-10 19:09:09 -070024
Andreas Gampe46651672017-04-07 09:00:04 -070025public class Test905 {
Alex Light22d8e482018-07-26 16:06:15 -070026 // Taken from jdwp tests.
27 public static class MarkerObj {
28 public static int cnt = 0;
29 public void finalize() { cnt++; }
30 }
31 public static class GcMarker {
32 private final ReferenceQueue mQueue;
33 private final ArrayList<PhantomReference> mList;
34 public GcMarker() {
35 mQueue = new ReferenceQueue();
36 mList = new ArrayList<PhantomReference>(3);
37 }
38 public void add(Object referent) {
39 mList.add(new PhantomReference(referent, mQueue));
40 }
41 public void waitForGc() {
42 waitForGc(mList.size());
43 }
44 public void waitForGc(int numberOfExpectedFinalizations) {
45 if (numberOfExpectedFinalizations > mList.size()) {
46 throw new IllegalArgumentException("wait condition will never be met");
47 }
48 // Request finalization of objects, and subsequent reference enqueueing.
49 // Repeat until reference queue reaches expected size.
50 do {
51 System.runFinalization();
52 Runtime.getRuntime().gc();
53 try { Thread.sleep(10); } catch (Exception e) {}
54 } while (isLive(numberOfExpectedFinalizations));
55 }
56 private boolean isLive(int numberOfExpectedFinalizations) {
57 int numberFinalized = 0;
58 for (int i = 0, n = mList.size(); i < n; i++) {
59 if (mList.get(i).isEnqueued()) {
60 numberFinalized++;
61 }
62 }
63 return numberFinalized < numberOfExpectedFinalizations;
64 }
65 }
66
Andreas Gampe46651672017-04-07 09:00:04 -070067 public static void run() throws Exception {
Andreas Gampecc13b222016-10-10 19:09:09 -070068 doTest();
69 }
70
71 public static void doTest() throws Exception {
72 // Use a list to ensure objects must be allocated.
73 ArrayList<Object> l = new ArrayList<>(100);
74
75 setupObjectFreeCallback();
76
77 enableFreeTracking(true);
78 run(l);
79
80 enableFreeTracking(false);
81 run(l);
Mathieu Chartierf169e272017-03-28 12:59:38 -070082
83 enableFreeTracking(true);
84 stress();
Andreas Gampecc13b222016-10-10 19:09:09 -070085 }
86
87 private static void run(ArrayList<Object> l) {
88 allocate(l, 1);
89 l.clear();
90
Alex Light22d8e482018-07-26 16:06:15 -070091 gcAndWait();
Andreas Gampecc13b222016-10-10 19:09:09 -070092
Andreas Gampee54eee12016-10-20 19:03:58 -070093 getAndPrintTags();
Andreas Gampecc13b222016-10-10 19:09:09 -070094 System.out.println("---");
95
96 // Note: the reporting will not depend on the heap layout (which could be unstable). Walking
97 // the tag table should give us a stable output order.
98 for (int i = 10; i <= 1000; i *= 10) {
99 allocate(l, i);
100 }
101 l.clear();
102
Alex Light22d8e482018-07-26 16:06:15 -0700103 gcAndWait();
Andreas Gampecc13b222016-10-10 19:09:09 -0700104
Andreas Gampee54eee12016-10-20 19:03:58 -0700105 getAndPrintTags();
Andreas Gampecc13b222016-10-10 19:09:09 -0700106 System.out.println("---");
107
Alex Light22d8e482018-07-26 16:06:15 -0700108 gcAndWait();
Andreas Gampecc13b222016-10-10 19:09:09 -0700109
Andreas Gampee54eee12016-10-20 19:03:58 -0700110 getAndPrintTags();
Andreas Gampecc13b222016-10-10 19:09:09 -0700111 System.out.println("---");
112 }
113
Alex Light35a760d2019-02-12 14:24:38 -0800114 private static void stressAllocate(int i, BiConsumer<Integer, Object> saver) {
Andreas Gampea1705ea2017-03-28 20:12:13 -0700115 Object obj = new Object();
Andreas Gampe46651672017-04-07 09:00:04 -0700116 Main.setTag(obj, i);
Andreas Gampea1705ea2017-03-28 20:12:13 -0700117 setTag2(obj, i + 1);
Alex Light35a760d2019-02-12 14:24:38 -0800118 saver.accept(i, obj);
Andreas Gampea1705ea2017-03-28 20:12:13 -0700119 }
120
Mathieu Chartierf169e272017-03-28 12:59:38 -0700121 private static void stress() {
122 getCollectedTags(0);
123 getCollectedTags(1);
Alex Light35a760d2019-02-12 14:24:38 -0800124 final int num_obj = 400000;
125 final Object[] saved = new Object[num_obj/2];
126 // Allocate objects, Save every other one. We want to be sure that it's only the deleted objects
127 // that get their tags cleared and non-deleted objects correctly keep track of their tags.
128 for (int i = 1; i <= num_obj; ++i) {
129 stressAllocate(i, (idx, obj) -> {
130 if ((idx.intValue() - 1) % 2 == 0) {
131 saved[(idx.intValue() - 1)/2] = obj;
132 }
133 });
Mathieu Chartierf169e272017-03-28 12:59:38 -0700134 }
Alex Light22d8e482018-07-26 16:06:15 -0700135 gcAndWait();
Mathieu Chartierf169e272017-03-28 12:59:38 -0700136 long[] freedTags1 = getCollectedTags(0);
137 long[] freedTags2 = getCollectedTags(1);
Alex Light35a760d2019-02-12 14:24:38 -0800138 // Sort the freedtags
139 Arrays.sort(freedTags1);
140 Arrays.sort(freedTags2);
141 // Make sure we freed all the ones we expect to and both envs agree on this.
Mathieu Chartierf169e272017-03-28 12:59:38 -0700142 System.out.println("Free counts " + freedTags1.length + " " + freedTags2.length);
143 for (int i = 0; i < freedTags1.length; ++i) {
Andreas Gampea1705ea2017-03-28 20:12:13 -0700144 if (freedTags1[i] + 1 != freedTags2[i]) {
Alex Light35a760d2019-02-12 14:24:38 -0800145 System.out.println("Mismatched tags " + (freedTags1[i] + 1) + " " + freedTags2[i]);
146 }
147 }
148 // Make sure the saved-tags aren't present.
149 for (int i = 0; i < saved.length; i++) {
150 // index = (tag - 1)/2 --> (index * 2) + 1 = tag
151 long expectedTag1 = (i * 2) + 1;
152 if (Main.getTag(saved[i]) != expectedTag1) {
153 System.out.println("Saved object has unexpected tag in env 1. Expected "
154 + expectedTag1 + " got " + Main.getTag(saved[i]));
155 }
156 if (getTag2(saved[i]) != 1 + expectedTag1) {
157 System.out.println("Saved object has unexpected tag in env 2. Expected "
158 + (expectedTag1 + 1) + " got " + getTag2(saved[i]));
159 }
160 if (Arrays.binarySearch(freedTags1, expectedTag1) >= 0) {
161 System.out.println("Saved object was marked as deleted in env 1. Object was "
162 + expectedTag1);
163 }
164 if (Arrays.binarySearch(freedTags2, expectedTag1 + 1) >= 0) {
165 System.out.println("Saved object was marked as deleted in env 2. Object was "
166 + (expectedTag1 + 1));
Mathieu Chartierf169e272017-03-28 12:59:38 -0700167 }
168 }
169 }
170
Andreas Gampecc13b222016-10-10 19:09:09 -0700171 private static void allocate(ArrayList<Object> l, long tag) {
172 Object obj = new Object();
173 l.add(obj);
Andreas Gampe46651672017-04-07 09:00:04 -0700174 Main.setTag(obj, tag);
Andreas Gampecc13b222016-10-10 19:09:09 -0700175 }
176
Andreas Gampee54eee12016-10-20 19:03:58 -0700177 private static void getAndPrintTags() {
Mathieu Chartierf169e272017-03-28 12:59:38 -0700178 long[] freedTags = getCollectedTags(0);
Andreas Gampee54eee12016-10-20 19:03:58 -0700179 Arrays.sort(freedTags);
180 System.out.println(Arrays.toString(freedTags));
181 }
182
Alex Light22d8e482018-07-26 16:06:15 -0700183 private static GcMarker getMarker() {
184 GcMarker m = new GcMarker();
185 m.add(new MarkerObj());
186 return m;
187 }
188
189 private static void gcAndWait() {
190 GcMarker marker = getMarker();
191 marker.waitForGc();
192 }
193
Andreas Gampecc13b222016-10-10 19:09:09 -0700194 private static native void setupObjectFreeCallback();
195 private static native void enableFreeTracking(boolean enable);
Mathieu Chartierf169e272017-03-28 12:59:38 -0700196 private static native long[] getCollectedTags(int index);
Andreas Gampea1705ea2017-03-28 20:12:13 -0700197 private static native void setTag2(Object o, long tag);
Alex Light35a760d2019-02-12 14:24:38 -0800198 private static native long getTag2(Object o);
Andreas Gampecc13b222016-10-10 19:09:09 -0700199}