| // 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 |