// 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 #include #include #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 permutation(new intptr_t[count]); for (intptr_t i = 0; i < count; ++i) { permutation[i] = i; } std::function 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