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
14namespace dart {
15
16static CatchEntryMove NewMove(intptr_t src, intptr_t dst) {
17 return CatchEntryMove::FromSlot(CatchEntryMove::SourceKind::kTaggedSlot, src,
18 dst);
19}
20const auto kA = NewMove(1, 10);
21const auto kB = NewMove(2, 20);
22const auto kC = NewMove(3, 30);
23const auto kD = NewMove(4, 40);
24const auto kE = NewMove(5, 50);
25const auto kX = NewMove(-1, -10);
26
27const CatchEntryMove abcde[] = {kA, kB, kC, kD, kE};
28const CatchEntryMove abcdx[] = {kA, kB, kC, kD, kX};
29const CatchEntryMove xbcde[] = {kX, kB, kC, kD, kE};
30const CatchEntryMove abxde[] = {kA, kB, kX, kD, kE};
31const CatchEntryMove ab[] = {kA, kB};
32const CatchEntryMove de[] = {kD, kE};
33
34struct TestCaseMoves {
35 const CatchEntryMove* moves;
36 const intptr_t count;
37};
38
39void 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
67void 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
95ISOLATE_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