blob: 7ca32efd4458704ca4b5563a0bd3a813345ab0e1 [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <functional>
#include <memory>
#include <utility>
#include "platform/assert.h"
#include "vm/code_descriptors.h"
#include "vm/exceptions.h"
#include "vm/unit_test.h"
namespace dart {
static CatchEntryMove NewMove(intptr_t src, intptr_t dst) {
return CatchEntryMove::FromSlot(CatchEntryMove::SourceKind::kTaggedSlot, src,
dst);
}
const auto kA = NewMove(1, 10);
const auto kB = NewMove(2, 20);
const auto kC = NewMove(3, 30);
const auto kD = NewMove(4, 40);
const auto kE = NewMove(5, 50);
const auto kX = NewMove(-1, -10);
const CatchEntryMove abcde[] = {kA, kB, kC, kD, kE};
const CatchEntryMove abcdx[] = {kA, kB, kC, kD, kX};
const CatchEntryMove xbcde[] = {kX, kB, kC, kD, kE};
const CatchEntryMove abxde[] = {kA, kB, kX, kD, kE};
const CatchEntryMove ab[] = {kA, kB};
const CatchEntryMove de[] = {kD, kE};
struct TestCaseMoves {
const CatchEntryMove* moves;
const intptr_t count;
};
void RunTestCaseWithPermutations(const TestCaseMoves* mapping,
intptr_t* insert_permutation,
intptr_t count) {
CatchEntryMovesMapBuilder b;
for (intptr_t i = 0; i < count; ++i) {
auto expected_moves = mapping[insert_permutation[i]];
b.NewMapping(/*pc_offset=*/insert_permutation[i]);
for (intptr_t j = 0; j < expected_moves.count; ++j) {
b.Append(expected_moves.moves[j]);
}
b.EndMapping();
}
const auto& bytes = TypedData::Handle(b.FinalizeCatchEntryMovesMap());
CatchEntryMovesMapReader reader(bytes);
for (intptr_t i = 0; i < count; ++i) {
auto expected_moves = mapping[i];
auto read_moves = reader.ReadMovesForPcOffset(i);
EXPECT_EQ(expected_moves.count, read_moves->count());
for (intptr_t j = 0; j < expected_moves.count; ++j) {
EXPECT(expected_moves.moves[j] == read_moves->At(j));
}
free(read_moves);
}
}
void RunTestCase(const TestCaseMoves* mapping, intptr_t count) {
std::unique_ptr<intptr_t[]> permutation(new intptr_t[count]);
for (intptr_t i = 0; i < count; ++i) {
permutation[i] = i;
}
std::function<void(intptr_t)> run_all_permutations = [&](intptr_t offset) {
if (offset == count) {
RunTestCaseWithPermutations(mapping, &permutation[0], count);
} else {
for (intptr_t i = offset; i < count; ++i) {
const intptr_t start = permutation[offset];
const intptr_t replacement = permutation[i];
permutation[offset] = replacement;
permutation[i] = start;
run_all_permutations(offset + 1);
permutation[offset] = start;
permutation[i] = replacement;
}
}
};
run_all_permutations(0);
}
ISOLATE_UNIT_TEST_CASE(CatchEntryMoves) {
// Common prefix.
const TestCaseMoves test1[] = {
TestCaseMoves{
abcde,
ARRAY_SIZE(abcde),
},
TestCaseMoves{
abcdx,
ARRAY_SIZE(abcdx),
},
};
RunTestCase(test1, ARRAY_SIZE(test1));
// Common suffix.
const TestCaseMoves test2[] = {
TestCaseMoves{
abcde,
ARRAY_SIZE(abcde),
},
TestCaseMoves{
xbcde,
ARRAY_SIZE(xbcde),
},
};
RunTestCase(test2, ARRAY_SIZE(test2));
// Common prefix and suffix.
const TestCaseMoves test3[] = {
TestCaseMoves{
abcde,
ARRAY_SIZE(abcde),
},
TestCaseMoves{
abxde,
ARRAY_SIZE(abxde),
},
};
RunTestCase(test3, ARRAY_SIZE(test3));
// Subset of suffix.
const TestCaseMoves test4[] = {
TestCaseMoves{
abcde,
ARRAY_SIZE(abcde),
},
TestCaseMoves{
de,
ARRAY_SIZE(de),
},
};
RunTestCase(test4, ARRAY_SIZE(test4));
// Subset of prefix.
const TestCaseMoves test5[] = {
TestCaseMoves{
abcde,
ARRAY_SIZE(abcde),
},
TestCaseMoves{
ab,
ARRAY_SIZE(ab),
},
};
RunTestCase(test5, ARRAY_SIZE(test5));
// All moves (with duplicates).
const TestCaseMoves test6[] = {
TestCaseMoves{
abcde,
ARRAY_SIZE(abcde),
},
TestCaseMoves{
abcde,
ARRAY_SIZE(abcde),
},
TestCaseMoves{
abcdx,
ARRAY_SIZE(abcdx),
},
TestCaseMoves{
xbcde,
ARRAY_SIZE(xbcde),
},
TestCaseMoves{
abxde,
ARRAY_SIZE(abxde),
},
TestCaseMoves{
ab,
ARRAY_SIZE(ab),
},
TestCaseMoves{
de,
ARRAY_SIZE(de),
},
TestCaseMoves{
de,
ARRAY_SIZE(de),
},
};
RunTestCase(test6, ARRAY_SIZE(test6));
}
} // namespace dart