blob: 91fcc07d65b30f8cdaca71946c1a42fac1c6e8f6 [file] [log] [blame]
Igor Murashkinf31a00c2017-10-27 10:52:07 -07001/*
2 * Copyright (C) 2017 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
17#include "subtype_check_info.h"
18
19#include "gtest/gtest.h"
20#include "android-base/logging.h"
21
22namespace art {
23
24constexpr size_t BitString::kBitSizeAtPosition[BitString::kCapacity];
25constexpr size_t BitString::kCapacity;
26
27}; // namespace art
28
29using namespace art; // NOLINT
30
31// These helper functions are only used by the test,
32// so they are not in the main BitString class.
33std::string Stringify(BitString bit_string) {
34 std::stringstream ss;
35 ss << bit_string;
36 return ss.str();
37}
38
39BitStringChar MakeBitStringChar(size_t idx, size_t val) {
40 return BitStringChar(val, BitString::MaybeGetBitLengthAtPosition(idx));
41}
42
43BitStringChar MakeBitStringChar(size_t val) {
44 return BitStringChar(val, MinimumBitsToStore(val));
45}
46
47BitString MakeBitString(std::initializer_list<size_t> values = {}) {
48 CHECK_GE(BitString::kCapacity, values.size());
49
Igor Murashkin5573c372017-11-16 13:34:30 -080050 BitString bs{};
Igor Murashkinf31a00c2017-10-27 10:52:07 -070051
52 size_t i = 0;
53 for (size_t val : values) {
54 bs.SetAt(i, MakeBitStringChar(i, val));
55 ++i;
56 }
57
58 return bs;
59}
60
61template <typename T>
62size_t AsUint(const T& value) {
63 size_t uint_value = 0;
64 memcpy(&uint_value, &value, sizeof(value));
65 return uint_value;
66}
67
Vladimir Markodc682aa2018-01-04 18:42:57 +000068// Make max bistring, e.g. BitString[4095,15,2047] for {12,4,11}
Igor Murashkinf31a00c2017-10-27 10:52:07 -070069template <size_t kCount = BitString::kCapacity>
70BitString MakeBitStringMax() {
Igor Murashkin5573c372017-11-16 13:34:30 -080071 BitString bs{};
Igor Murashkinf31a00c2017-10-27 10:52:07 -070072
73 for (size_t i = 0; i < kCount; ++i) {
74 bs.SetAt(i,
75 MakeBitStringChar(i, MaxInt<BitStringChar::StorageType>(BitString::kBitSizeAtPosition[i])));
76 }
77
78 return bs;
79}
80
81BitString SetBitStringCharAt(BitString bit_string, size_t i, size_t val) {
82 BitString bs = bit_string;
83 bs.SetAt(i, MakeBitStringChar(i, val));
84 return bs;
85}
86
87struct SubtypeCheckInfoTest : public ::testing::Test {
88 protected:
89 virtual void SetUp() {
90 android::base::InitLogging(/*argv*/nullptr);
91 }
92
93 virtual void TearDown() {
94 }
95
96 static SubtypeCheckInfo MakeSubtypeCheckInfo(BitString path_to_root = {},
97 BitStringChar next = {},
98 bool overflow = false,
99 size_t depth = 1u) {
100 // Depth=1 is good default because it will go through all state transitions,
101 // and its children will also go through all state transitions.
102 return SubtypeCheckInfo(path_to_root, next, overflow, depth);
103 }
104
105 static SubtypeCheckInfo MakeSubtypeCheckInfoInfused(BitString bs = {},
106 bool overflow = false,
107 size_t depth = 1u) {
108 // Depth=1 is good default because it will go through all state transitions,
109 // and its children will also go through all state transitions.
110 SubtypeCheckBits iod;
111 iod.bitstring_ = bs;
112 iod.overflow_ = overflow;
113 return SubtypeCheckInfo::Create(iod, depth);
114 }
115
116 static SubtypeCheckInfo MakeSubtypeCheckInfoUnchecked(BitString bs = {},
117 bool overflow = false,
118 size_t depth = 1u) {
119 // Depth=1 is good default because it will go through all state transitions,
120 // and its children will also go through all state transitions.
121 return SubtypeCheckInfo::MakeUnchecked(bs, overflow, depth);
122 }
123
124 static bool HasNext(SubtypeCheckInfo io) {
125 return io.HasNext();
126 }
127
128 static BitString GetPathToRoot(SubtypeCheckInfo io) {
129 return io.GetPathToRoot();
130 }
131
132 // Create an SubtypeCheckInfo with the same depth, but with everything else reset.
133 // Returns: SubtypeCheckInfo in the Uninitialized state.
134 static SubtypeCheckInfo CopyCleared(SubtypeCheckInfo sc) {
Igor Murashkin5573c372017-11-16 13:34:30 -0800135 SubtypeCheckInfo cleared_copy{};
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700136 cleared_copy.depth_ = sc.depth_;
137 DCHECK_EQ(SubtypeCheckInfo::kUninitialized, cleared_copy.GetState());
138 return cleared_copy;
139 }
140};
141
142const char* GetExpectedMessageForDeathTest(const char* msg) {
143#ifdef ART_TARGET_ANDROID
144 // On Android, dcheck failure messages go to logcat,
145 // which gtest death tests does not check, and thus the tests would fail with
146 // "unexpected message ''"
147 UNUSED(msg);
148 return ""; // Still ensures there was a bad return code, but match anything.
149#else
150 return msg;
151#endif
152}
153
154TEST_F(SubtypeCheckInfoTest, IllegalValues) {
155 // This test relies on BitString being at least 3 large.
156 // It will need to be updated otherwise.
157 ASSERT_LE(3u, BitString::kCapacity);
158
159 // Illegal values during construction would cause a Dcheck failure and crash.
160 ASSERT_DEATH(MakeSubtypeCheckInfo(MakeBitString({1u}),
161 /*next*/MakeBitStringChar(0),
162 /*overflow*/false,
163 /*depth*/0u),
164 GetExpectedMessageForDeathTest("Path was too long for the depth"));
165 ASSERT_DEATH(MakeSubtypeCheckInfoInfused(MakeBitString({1u, 1u}),
166 /*overflow*/false,
167 /*depth*/0u),
168 GetExpectedMessageForDeathTest("Bitstring too long for depth"));
169 ASSERT_DEATH(MakeSubtypeCheckInfo(MakeBitString({1u}),
170 /*next*/MakeBitStringChar(0),
171 /*overflow*/false,
172 /*depth*/1u),
173 GetExpectedMessageForDeathTest("Expected \\(Assigned\\|Initialized\\) "
174 "state to have >0 Next value"));
175 ASSERT_DEATH(MakeSubtypeCheckInfoInfused(MakeBitString({0u, 2u, 1u}),
176 /*overflow*/false,
177 /*depth*/2u),
178 GetExpectedMessageForDeathTest("Path to root had non-0s following 0s"));
179 ASSERT_DEATH(MakeSubtypeCheckInfo(MakeBitString({0u, 2u}),
180 /*next*/MakeBitStringChar(1u),
181 /*overflow*/false,
182 /*depth*/2u),
183 GetExpectedMessageForDeathTest("Path to root had non-0s following 0s"));
184 ASSERT_DEATH(MakeSubtypeCheckInfo(MakeBitString({0u, 1u, 1u}),
185 /*next*/MakeBitStringChar(0),
186 /*overflow*/false,
187 /*depth*/3u),
188 GetExpectedMessageForDeathTest("Path to root had non-0s following 0s"));
189
190 // These are really slow (~1sec per death test on host),
191 // keep them down to a minimum.
192}
193
194TEST_F(SubtypeCheckInfoTest, States) {
195 EXPECT_EQ(SubtypeCheckInfo::kUninitialized, MakeSubtypeCheckInfo().GetState());
196 EXPECT_EQ(SubtypeCheckInfo::kInitialized,
197 MakeSubtypeCheckInfo(/*path*/{}, /*next*/MakeBitStringChar(1)).GetState());
198 EXPECT_EQ(SubtypeCheckInfo::kOverflowed,
199 MakeSubtypeCheckInfo(/*path*/{},
200 /*next*/MakeBitStringChar(1),
201 /*overflow*/true,
202 /*depth*/1u).GetState());
203 EXPECT_EQ(SubtypeCheckInfo::kAssigned,
204 MakeSubtypeCheckInfo(/*path*/MakeBitString({1u}),
205 /*next*/MakeBitStringChar(1),
206 /*overflow*/false,
207 /*depth*/1u).GetState());
208
209 // Test edge conditions: depth == BitString::kCapacity (No Next value).
210 EXPECT_EQ(SubtypeCheckInfo::kAssigned,
211 MakeSubtypeCheckInfo(/*path*/MakeBitStringMax(),
212 /*next*/MakeBitStringChar(0),
213 /*overflow*/false,
214 /*depth*/BitString::kCapacity).GetState());
215 EXPECT_EQ(SubtypeCheckInfo::kInitialized,
216 MakeSubtypeCheckInfo(/*path*/MakeBitStringMax<BitString::kCapacity - 1u>(),
217 /*next*/MakeBitStringChar(0),
218 /*overflow*/false,
219 /*depth*/BitString::kCapacity).GetState());
220 // Test edge conditions: depth > BitString::kCapacity (Must overflow).
221 EXPECT_EQ(SubtypeCheckInfo::kOverflowed,
222 MakeSubtypeCheckInfo(/*path*/MakeBitStringMax(),
223 /*next*/MakeBitStringChar(0),
224 /*overflow*/true,
225 /*depth*/BitString::kCapacity + 1u).GetState());
226}
227
228TEST_F(SubtypeCheckInfoTest, NextValue) {
229 // Validate "Next" is correctly aliased as the Bitstring[Depth] character.
230 EXPECT_EQ(MakeBitStringChar(1u), MakeSubtypeCheckInfoUnchecked(MakeBitString({1u, 2u, 3u}),
231 /*overflow*/false,
232 /*depth*/0u).GetNext());
233 EXPECT_EQ(MakeBitStringChar(2u), MakeSubtypeCheckInfoUnchecked(MakeBitString({1u, 2u, 3u}),
234 /*overflow*/false,
235 /*depth*/1u).GetNext());
236 EXPECT_EQ(MakeBitStringChar(3u), MakeSubtypeCheckInfoUnchecked(MakeBitString({1u, 2u, 3u}),
237 /*overflow*/false,
238 /*depth*/2u).GetNext());
239 EXPECT_EQ(MakeBitStringChar(1u), MakeSubtypeCheckInfoUnchecked(MakeBitString({0u, 2u, 1u}),
240 /*overflow*/false,
241 /*depth*/2u).GetNext());
242 // Test edge conditions: depth == BitString::kCapacity (No Next value).
243 EXPECT_FALSE(HasNext(MakeSubtypeCheckInfoUnchecked(MakeBitStringMax<BitString::kCapacity>(),
244 /*overflow*/false,
245 /*depth*/BitString::kCapacity)));
246 // Anything with depth >= BitString::kCapacity has no next value.
247 EXPECT_FALSE(HasNext(MakeSubtypeCheckInfoUnchecked(MakeBitStringMax<BitString::kCapacity>(),
248 /*overflow*/false,
249 /*depth*/BitString::kCapacity + 1u)));
250 EXPECT_FALSE(HasNext(MakeSubtypeCheckInfoUnchecked(MakeBitStringMax(),
251 /*overflow*/false,
252 /*depth*/std::numeric_limits<size_t>::max())));
253}
254
255template <size_t kPos = BitString::kCapacity>
256size_t LenForPos() { return BitString::GetBitLengthTotalAtPosition(kPos); }
257
258TEST_F(SubtypeCheckInfoTest, EncodedPathToRoot) {
259 using StorageType = BitString::StorageType;
260
Vladimir Markodc682aa2018-01-04 18:42:57 +0000261 SubtypeCheckInfo sci =
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700262 MakeSubtypeCheckInfo(/*path_to_root*/MakeBitStringMax(),
Igor Murashkin5573c372017-11-16 13:34:30 -0800263 /*next*/BitStringChar{},
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700264 /*overflow*/false,
265 /*depth*/BitString::kCapacity);
Vladimir Markodc682aa2018-01-04 18:42:57 +0000266 // 0b000...111 where LSB == 1, and trailing 1s = the maximum bitstring representation.
267 EXPECT_EQ(MaxInt<StorageType>(LenForPos()), sci.GetEncodedPathToRoot());
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700268
269 // The rest of this test is written assuming kCapacity == 3 for convenience.
270 // Please update the test if this changes.
271 ASSERT_EQ(3u, BitString::kCapacity);
272 ASSERT_EQ(12u, BitString::kBitSizeAtPosition[0]);
Vladimir Markodc682aa2018-01-04 18:42:57 +0000273 ASSERT_EQ(4u, BitString::kBitSizeAtPosition[1]);
274 ASSERT_EQ(11u, BitString::kBitSizeAtPosition[2]);
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700275
Vladimir Markodc682aa2018-01-04 18:42:57 +0000276 SubtypeCheckInfo sci2 =
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700277 MakeSubtypeCheckInfoUnchecked(MakeBitStringMax<2u>(),
278 /*overflow*/false,
279 /*depth*/BitString::kCapacity);
280
Vladimir Markodc682aa2018-01-04 18:42:57 +0000281#define MAKE_ENCODED_PATH(pos0, pos1, pos2) \
282 (((pos0) << 0) | \
283 ((pos1) << BitString::kBitSizeAtPosition[0]) | \
284 ((pos2) << (BitString::kBitSizeAtPosition[0] + BitString::kBitSizeAtPosition[1])))
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700285
Vladimir Markodc682aa2018-01-04 18:42:57 +0000286 EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b1111, 0b0),
287 sci2.GetEncodedPathToRoot());
288 EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b1111, 0b11111111111),
289 sci2.GetEncodedPathToRootMask());
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700290
Vladimir Markodc682aa2018-01-04 18:42:57 +0000291 SubtypeCheckInfo sci3 =
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700292 MakeSubtypeCheckInfoUnchecked(MakeBitStringMax<2u>(),
293 /*overflow*/false,
294 /*depth*/BitString::kCapacity - 1u);
295
Vladimir Markodc682aa2018-01-04 18:42:57 +0000296 EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b1111, 0b0),
297 sci3.GetEncodedPathToRoot());
298 EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b1111, 0b0),
299 sci3.GetEncodedPathToRootMask());
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700300
Vladimir Markodc682aa2018-01-04 18:42:57 +0000301 SubtypeCheckInfo sci4 =
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700302 MakeSubtypeCheckInfoUnchecked(MakeBitString({0b1010101u}),
303 /*overflow*/false,
304 /*depth*/BitString::kCapacity - 2u);
305
Vladimir Markodc682aa2018-01-04 18:42:57 +0000306 EXPECT_EQ(MAKE_ENCODED_PATH(0b1010101u, 0b0000, 0b0), sci4.GetEncodedPathToRoot());
307 EXPECT_EQ(MAKE_ENCODED_PATH(MaxInt<BitString::StorageType>(12), 0b0000, 0b0),
308 sci4.GetEncodedPathToRootMask());
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700309}
310
311TEST_F(SubtypeCheckInfoTest, NewForRoot) {
Vladimir Markodc682aa2018-01-04 18:42:57 +0000312 SubtypeCheckInfo sci = SubtypeCheckInfo::CreateRoot();
313 EXPECT_EQ(SubtypeCheckInfo::kAssigned, sci.GetState()); // Root is always assigned.
314 EXPECT_EQ(0u, GetPathToRoot(sci).Length()); // Root's path length is 0.
315 EXPECT_TRUE(HasNext(sci)); // Root always has a "Next".
316 EXPECT_EQ(MakeBitStringChar(1u), sci.GetNext()); // Next>=1 to disambiguate from Uninitialized.
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700317}
318
319TEST_F(SubtypeCheckInfoTest, CopyCleared) {
320 SubtypeCheckInfo root = SubtypeCheckInfo::CreateRoot();
321 EXPECT_EQ(MakeBitStringChar(1u), root.GetNext());
322
323 SubtypeCheckInfo childC = root.CreateChild(/*assign*/true);
324 EXPECT_EQ(SubtypeCheckInfo::kAssigned, childC.GetState());
325 EXPECT_EQ(MakeBitStringChar(2u), root.GetNext()); // Next incremented for Assign.
326 EXPECT_EQ(MakeBitString({1u}), GetPathToRoot(childC));
327
328 SubtypeCheckInfo cleared_copy = CopyCleared(childC);
329 EXPECT_EQ(SubtypeCheckInfo::kUninitialized, cleared_copy.GetState());
330 EXPECT_EQ(MakeBitString({}), GetPathToRoot(cleared_copy));
331
332 // CopyCleared is just a thin wrapper around value-init and providing the depth.
333 SubtypeCheckInfo cleared_copy_value =
Igor Murashkin5573c372017-11-16 13:34:30 -0800334 SubtypeCheckInfo::Create(SubtypeCheckBits{}, /*depth*/1u);
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700335 EXPECT_EQ(SubtypeCheckInfo::kUninitialized, cleared_copy_value.GetState());
336 EXPECT_EQ(MakeBitString({}), GetPathToRoot(cleared_copy_value));
337}
338
339TEST_F(SubtypeCheckInfoTest, NewForChild2) {
340 SubtypeCheckInfo root = SubtypeCheckInfo::CreateRoot();
341 EXPECT_EQ(MakeBitStringChar(1u), root.GetNext());
342
343 SubtypeCheckInfo childC = root.CreateChild(/*assign*/true);
344 EXPECT_EQ(SubtypeCheckInfo::kAssigned, childC.GetState());
345 EXPECT_EQ(MakeBitStringChar(2u), root.GetNext()); // Next incremented for Assign.
346 EXPECT_EQ(MakeBitString({1u}), GetPathToRoot(childC));
347}
348
349TEST_F(SubtypeCheckInfoTest, NewForChild) {
350 SubtypeCheckInfo root = SubtypeCheckInfo::CreateRoot();
351 EXPECT_EQ(MakeBitStringChar(1u), root.GetNext());
352
353 SubtypeCheckInfo childA = root.CreateChild(/*assign*/false);
354 EXPECT_EQ(SubtypeCheckInfo::kInitialized, childA.GetState());
355 EXPECT_EQ(MakeBitStringChar(1u), root.GetNext()); // Next unchanged for Initialize.
356 EXPECT_EQ(MakeBitString({}), GetPathToRoot(childA));
357
358 SubtypeCheckInfo childB = root.CreateChild(/*assign*/false);
359 EXPECT_EQ(SubtypeCheckInfo::kInitialized, childB.GetState());
360 EXPECT_EQ(MakeBitStringChar(1u), root.GetNext()); // Next unchanged for Initialize.
361 EXPECT_EQ(MakeBitString({}), GetPathToRoot(childB));
362
363 SubtypeCheckInfo childC = root.CreateChild(/*assign*/true);
364 EXPECT_EQ(SubtypeCheckInfo::kAssigned, childC.GetState());
365 EXPECT_EQ(MakeBitStringChar(2u), root.GetNext()); // Next incremented for Assign.
366 EXPECT_EQ(MakeBitString({1u}), GetPathToRoot(childC));
367
368 {
369 size_t cur_depth = 1u;
370 SubtypeCheckInfo latest_child = childC;
371 while (cur_depth != BitString::kCapacity) {
372 latest_child = latest_child.CreateChild(/*assign*/true);
373 ASSERT_EQ(SubtypeCheckInfo::kAssigned, latest_child.GetState());
374 ASSERT_EQ(cur_depth + 1u, GetPathToRoot(latest_child).Length());
375 cur_depth++;
376 }
377
378 // Future assignments will result in a too-deep overflow.
379 SubtypeCheckInfo child_of_deep = latest_child.CreateChild(/*assign*/true);
380 EXPECT_EQ(SubtypeCheckInfo::kOverflowed, child_of_deep.GetState());
381 EXPECT_EQ(GetPathToRoot(latest_child), GetPathToRoot(child_of_deep));
382
383 // Assignment of too-deep overflow also causes overflow.
384 SubtypeCheckInfo child_of_deep_2 = child_of_deep.CreateChild(/*assign*/true);
385 EXPECT_EQ(SubtypeCheckInfo::kOverflowed, child_of_deep_2.GetState());
386 EXPECT_EQ(GetPathToRoot(child_of_deep), GetPathToRoot(child_of_deep_2));
387 }
388
389 {
390 size_t cur_next = 2u;
391 while (true) {
392 if (cur_next == MaxInt<BitString::StorageType>(BitString::kBitSizeAtPosition[0u])) {
393 break;
394 }
395
396 SubtypeCheckInfo child = root.CreateChild(/*assign*/true);
397 ASSERT_EQ(SubtypeCheckInfo::kAssigned, child.GetState());
398 ASSERT_EQ(MakeBitStringChar(cur_next+1u), root.GetNext());
399 ASSERT_EQ(MakeBitString({cur_next}), GetPathToRoot(child));
400
401 cur_next++;
402 }
403 // Now the root will be in a state that further assigns will be too-wide overflow.
404
405 // Initialization still succeeds.
406 SubtypeCheckInfo child = root.CreateChild(/*assign*/false);
407 EXPECT_EQ(SubtypeCheckInfo::kInitialized, child.GetState());
408 EXPECT_EQ(MakeBitStringChar(cur_next), root.GetNext());
409 EXPECT_EQ(MakeBitString({}), GetPathToRoot(child));
410
411 // Assignment goes to too-wide Overflow.
412 SubtypeCheckInfo child_of = root.CreateChild(/*assign*/true);
413 EXPECT_EQ(SubtypeCheckInfo::kOverflowed, child_of.GetState());
414 EXPECT_EQ(MakeBitStringChar(cur_next), root.GetNext());
415 EXPECT_EQ(MakeBitString({}), GetPathToRoot(child_of));
416
417 // Assignment of overflowed child still succeeds.
418 // The path to root is the same.
419 SubtypeCheckInfo child_of2 = child_of.CreateChild(/*assign*/true);
420 EXPECT_EQ(SubtypeCheckInfo::kOverflowed, child_of2.GetState());
421 EXPECT_EQ(GetPathToRoot(child_of), GetPathToRoot(child_of2));
422 }
423}