1 | // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include <functional> |
6 | #include <memory> |
7 | #include <utility> |
8 | |
9 | #include "platform/assert.h" |
10 | #include "vm/code_descriptors.h" |
11 | #include "vm/exceptions.h" |
12 | #include "vm/unit_test.h" |
13 | |
14 | namespace dart { |
15 | |
16 | static CatchEntryMove NewMove(intptr_t src, intptr_t dst) { |
17 | return CatchEntryMove::FromSlot(CatchEntryMove::SourceKind::kTaggedSlot, src, |
18 | dst); |
19 | } |
20 | const auto kA = NewMove(1, 10); |
21 | const auto kB = NewMove(2, 20); |
22 | const auto kC = NewMove(3, 30); |
23 | const auto kD = NewMove(4, 40); |
24 | const auto kE = NewMove(5, 50); |
25 | const auto kX = NewMove(-1, -10); |
26 | |
27 | const CatchEntryMove abcde[] = {kA, kB, kC, kD, kE}; |
28 | const CatchEntryMove abcdx[] = {kA, kB, kC, kD, kX}; |
29 | const CatchEntryMove xbcde[] = {kX, kB, kC, kD, kE}; |
30 | const CatchEntryMove abxde[] = {kA, kB, kX, kD, kE}; |
31 | const CatchEntryMove ab[] = {kA, kB}; |
32 | const CatchEntryMove de[] = {kD, kE}; |
33 | |
34 | struct TestCaseMoves { |
35 | const CatchEntryMove* moves; |
36 | const intptr_t count; |
37 | }; |
38 | |
39 | void RunTestCaseWithPermutations(const TestCaseMoves* mapping, |
40 | intptr_t* insert_permutation, |
41 | intptr_t count) { |
42 | CatchEntryMovesMapBuilder b; |
43 | |
44 | for (intptr_t i = 0; i < count; ++i) { |
45 | auto expected_moves = mapping[insert_permutation[i]]; |
46 | b.NewMapping(/*pc_offset=*/insert_permutation[i]); |
47 | for (intptr_t j = 0; j < expected_moves.count; ++j) { |
48 | b.Append(expected_moves.moves[j]); |
49 | } |
50 | b.EndMapping(); |
51 | } |
52 | |
53 | const auto& bytes = TypedData::Handle(b.FinalizeCatchEntryMovesMap()); |
54 | CatchEntryMovesMapReader reader(bytes); |
55 | |
56 | for (intptr_t i = 0; i < count; ++i) { |
57 | auto expected_moves = mapping[i]; |
58 | auto read_moves = reader.ReadMovesForPcOffset(i); |
59 | EXPECT_EQ(expected_moves.count, read_moves->count()); |
60 | for (intptr_t j = 0; j < expected_moves.count; ++j) { |
61 | EXPECT(expected_moves.moves[j] == read_moves->At(j)); |
62 | } |
63 | free(read_moves); |
64 | } |
65 | } |
66 | |
67 | void RunTestCase(const TestCaseMoves* mapping, intptr_t count) { |
68 | std::unique_ptr<intptr_t[]> permutation(new intptr_t[count]); |
69 | for (intptr_t i = 0; i < count; ++i) { |
70 | permutation[i] = i; |
71 | } |
72 | |
73 | std::function<void(intptr_t)> run_all_permutations = [&](intptr_t offset) { |
74 | if (offset == count) { |
75 | RunTestCaseWithPermutations(mapping, &permutation[0], count); |
76 | } else { |
77 | for (intptr_t i = offset; i < count; ++i) { |
78 | const intptr_t start = permutation[offset]; |
79 | const intptr_t replacement = permutation[i]; |
80 | |
81 | permutation[offset] = replacement; |
82 | permutation[i] = start; |
83 | |
84 | run_all_permutations(offset + 1); |
85 | |
86 | permutation[offset] = start; |
87 | permutation[i] = replacement; |
88 | } |
89 | } |
90 | }; |
91 | |
92 | run_all_permutations(0); |
93 | } |
94 | |
95 | ISOLATE_UNIT_TEST_CASE(CatchEntryMoves) { |
96 | // Common prefix. |
97 | const TestCaseMoves test1[] = { |
98 | TestCaseMoves{ |
99 | abcde, |
100 | ARRAY_SIZE(abcde), |
101 | }, |
102 | TestCaseMoves{ |
103 | abcdx, |
104 | ARRAY_SIZE(abcdx), |
105 | }, |
106 | }; |
107 | RunTestCase(test1, ARRAY_SIZE(test1)); |
108 | |
109 | // Common suffix. |
110 | const TestCaseMoves test2[] = { |
111 | TestCaseMoves{ |
112 | abcde, |
113 | ARRAY_SIZE(abcde), |
114 | }, |
115 | TestCaseMoves{ |
116 | xbcde, |
117 | ARRAY_SIZE(xbcde), |
118 | }, |
119 | }; |
120 | RunTestCase(test2, ARRAY_SIZE(test2)); |
121 | |
122 | // Common prefix and suffix. |
123 | const TestCaseMoves test3[] = { |
124 | TestCaseMoves{ |
125 | abcde, |
126 | ARRAY_SIZE(abcde), |
127 | }, |
128 | TestCaseMoves{ |
129 | abxde, |
130 | ARRAY_SIZE(abxde), |
131 | }, |
132 | }; |
133 | RunTestCase(test3, ARRAY_SIZE(test3)); |
134 | |
135 | // Subset of suffix. |
136 | const TestCaseMoves test4[] = { |
137 | TestCaseMoves{ |
138 | abcde, |
139 | ARRAY_SIZE(abcde), |
140 | }, |
141 | TestCaseMoves{ |
142 | de, |
143 | ARRAY_SIZE(de), |
144 | }, |
145 | }; |
146 | RunTestCase(test4, ARRAY_SIZE(test4)); |
147 | |
148 | // Subset of prefix. |
149 | const TestCaseMoves test5[] = { |
150 | TestCaseMoves{ |
151 | abcde, |
152 | ARRAY_SIZE(abcde), |
153 | }, |
154 | TestCaseMoves{ |
155 | ab, |
156 | ARRAY_SIZE(ab), |
157 | }, |
158 | }; |
159 | RunTestCase(test5, ARRAY_SIZE(test5)); |
160 | |
161 | // All moves (with duplicates). |
162 | const TestCaseMoves test6[] = { |
163 | TestCaseMoves{ |
164 | abcde, |
165 | ARRAY_SIZE(abcde), |
166 | }, |
167 | TestCaseMoves{ |
168 | abcde, |
169 | ARRAY_SIZE(abcde), |
170 | }, |
171 | TestCaseMoves{ |
172 | abcdx, |
173 | ARRAY_SIZE(abcdx), |
174 | }, |
175 | TestCaseMoves{ |
176 | xbcde, |
177 | ARRAY_SIZE(xbcde), |
178 | }, |
179 | TestCaseMoves{ |
180 | abxde, |
181 | ARRAY_SIZE(abxde), |
182 | }, |
183 | TestCaseMoves{ |
184 | ab, |
185 | ARRAY_SIZE(ab), |
186 | }, |
187 | TestCaseMoves{ |
188 | de, |
189 | ARRAY_SIZE(de), |
190 | }, |
191 | TestCaseMoves{ |
192 | de, |
193 | ARRAY_SIZE(de), |
194 | }, |
195 | }; |
196 | RunTestCase(test6, ARRAY_SIZE(test6)); |
197 | } |
198 | |
199 | } // namespace dart |
200 | |