| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/interpreter/bytecode-array-builder.h" | 7 #include "src/interpreter/bytecode-array-builder.h" |
| 8 #include "src/interpreter/bytecode-register-allocator.h" | 8 #include "src/interpreter/bytecode-register-allocator.h" |
| 9 #include "test/unittests/test-utils.h" | 9 #include "test/unittests/test-utils.h" |
| 10 | 10 |
| 11 namespace v8 { | 11 namespace v8 { |
| 12 namespace internal { | 12 namespace internal { |
| 13 namespace interpreter { | 13 namespace interpreter { |
| 14 | 14 |
| 15 class TemporaryRegisterAllocatorTest : public TestWithIsolateAndZone { | 15 class BytecodeRegisterAllocatorTest : public TestWithIsolateAndZone { |
| 16 public: | 16 public: |
| 17 TemporaryRegisterAllocatorTest() : allocator_(zone(), 0) {} | 17 BytecodeRegisterAllocatorTest() : allocator_(0) {} |
| 18 ~TemporaryRegisterAllocatorTest() override {} | 18 ~BytecodeRegisterAllocatorTest() override {} |
| 19 TemporaryRegisterAllocator* allocator() { return &allocator_; } | 19 |
| 20 BytecodeRegisterAllocator* allocator() { return &allocator_; } |
| 20 | 21 |
| 21 private: | 22 private: |
| 22 TemporaryRegisterAllocator allocator_; | 23 BytecodeRegisterAllocator allocator_; |
| 23 }; | 24 }; |
| 24 | 25 |
| 25 TEST_F(TemporaryRegisterAllocatorTest, FirstAllocation) { | 26 TEST_F(BytecodeRegisterAllocatorTest, SimpleAllocations) { |
| 26 CHECK_EQ(allocator()->allocation_count(), 0); | 27 CHECK_EQ(allocator()->maximum_register_count(), 0); |
| 27 int reg0_index = allocator()->BorrowTemporaryRegister(); | 28 Register reg0 = allocator()->NewRegister(); |
| 28 CHECK_EQ(reg0_index, 0); | 29 CHECK_EQ(reg0.index(), 0); |
| 29 CHECK_EQ(allocator()->allocation_count(), 1); | 30 CHECK_EQ(allocator()->maximum_register_count(), 1); |
| 30 CHECK(allocator()->RegisterIsLive(Register(reg0_index))); | 31 CHECK_EQ(allocator()->next_register_index(), 1); |
| 31 allocator()->ReturnTemporaryRegister(reg0_index); | 32 CHECK(allocator()->RegisterIsLive(reg0)); |
| 32 CHECK(!allocator()->RegisterIsLive(Register(reg0_index))); | 33 |
| 33 CHECK_EQ(allocator()->allocation_count(), 1); | 34 allocator()->ReleaseRegisters(0); |
| 34 CHECK(allocator()->first_temporary_register() == Register(0)); | 35 CHECK(!allocator()->RegisterIsLive(reg0)); |
| 35 CHECK(allocator()->last_temporary_register() == Register(0)); | 36 CHECK_EQ(allocator()->maximum_register_count(), 1); |
| 37 CHECK_EQ(allocator()->next_register_index(), 0); |
| 38 |
| 39 reg0 = allocator()->NewRegister(); |
| 40 Register reg1 = allocator()->NewRegister(); |
| 41 CHECK_EQ(reg0.index(), 0); |
| 42 CHECK_EQ(reg1.index(), 1); |
| 43 CHECK(allocator()->RegisterIsLive(reg0)); |
| 44 CHECK(allocator()->RegisterIsLive(reg1)); |
| 45 CHECK_EQ(allocator()->maximum_register_count(), 2); |
| 46 CHECK_EQ(allocator()->next_register_index(), 2); |
| 47 |
| 48 allocator()->ReleaseRegisters(1); |
| 49 CHECK(allocator()->RegisterIsLive(reg0)); |
| 50 CHECK(!allocator()->RegisterIsLive(reg1)); |
| 51 CHECK_EQ(allocator()->maximum_register_count(), 2); |
| 52 CHECK_EQ(allocator()->next_register_index(), 1); |
| 36 } | 53 } |
| 37 | 54 |
| 38 TEST_F(TemporaryRegisterAllocatorTest, SimpleAllocations) { | 55 TEST_F(BytecodeRegisterAllocatorTest, RegisterListAllocations) { |
| 39 for (int i = 0; i < 13; i++) { | 56 CHECK_EQ(allocator()->maximum_register_count(), 0); |
| 40 int reg_index = allocator()->BorrowTemporaryRegister(); | 57 RegisterList reg_list = allocator()->NewRegisterList(3); |
| 41 CHECK_EQ(reg_index, i); | 58 CHECK_EQ(reg_list.first_register().index(), 0); |
| 42 CHECK_EQ(allocator()->allocation_count(), i + 1); | 59 CHECK_EQ(reg_list.register_count(), 3); |
| 43 } | 60 CHECK_EQ(reg_list[0].index(), 0); |
| 44 for (int i = 0; i < 13; i++) { | 61 CHECK_EQ(reg_list[1].index(), 1); |
| 45 CHECK(allocator()->RegisterIsLive(Register(i))); | 62 CHECK_EQ(reg_list[2].index(), 2); |
| 46 allocator()->ReturnTemporaryRegister(i); | 63 CHECK_EQ(allocator()->maximum_register_count(), 3); |
| 47 CHECK(!allocator()->RegisterIsLive(Register(i))); | 64 CHECK_EQ(allocator()->next_register_index(), 3); |
| 48 int reg_index = allocator()->BorrowTemporaryRegister(); | 65 CHECK(allocator()->RegisterIsLive(reg_list[2])); |
| 49 CHECK_EQ(reg_index, i); | |
| 50 CHECK_EQ(allocator()->allocation_count(), 13); | |
| 51 } | |
| 52 for (int i = 0; i < 13; i++) { | |
| 53 CHECK(allocator()->RegisterIsLive(Register(i))); | |
| 54 allocator()->ReturnTemporaryRegister(i); | |
| 55 CHECK(!allocator()->RegisterIsLive(Register(i))); | |
| 56 } | |
| 57 } | |
| 58 | 66 |
| 59 TEST_F(TemporaryRegisterAllocatorTest, SimpleRangeAllocation) { | 67 Register reg = allocator()->NewRegister(); |
| 60 static const int kRunLength = 7; | 68 RegisterList reg_list_2 = allocator()->NewRegisterList(2); |
| 61 int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); | 69 CHECK_EQ(reg.index(), 3); |
| 62 CHECK(!allocator()->RegisterIsLive(Register(start))); | 70 CHECK_EQ(reg_list_2.first_register().index(), 4); |
| 63 for (int i = 0; i < kRunLength; i++) { | 71 CHECK_EQ(reg_list_2.register_count(), 2); |
| 64 CHECK(!allocator()->RegisterIsLive(Register(start + i))); | 72 CHECK_EQ(reg_list_2[0].index(), 4); |
| 65 allocator()->BorrowConsecutiveTemporaryRegister(start + i); | 73 CHECK_EQ(reg_list_2[1].index(), 5); |
| 66 CHECK(allocator()->RegisterIsLive(Register(start + i))); | 74 CHECK_EQ(allocator()->maximum_register_count(), 6); |
| 67 } | 75 CHECK_EQ(allocator()->next_register_index(), 6); |
| 68 } | 76 CHECK(allocator()->RegisterIsLive(reg)); |
| 77 CHECK(allocator()->RegisterIsLive(reg_list_2[1])); |
| 69 | 78 |
| 70 TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingFree) { | 79 allocator()->ReleaseRegisters(reg.index()); |
| 71 static const int kFreeCount = 3; | 80 CHECK(!allocator()->RegisterIsLive(reg)); |
| 72 static const int kRunLength = 6; | 81 CHECK(!allocator()->RegisterIsLive(reg_list_2[0])); |
| 82 CHECK(!allocator()->RegisterIsLive(reg_list_2[1])); |
| 83 CHECK(allocator()->RegisterIsLive(reg_list[2])); |
| 84 CHECK_EQ(allocator()->maximum_register_count(), 6); |
| 85 CHECK_EQ(allocator()->next_register_index(), 3); |
| 73 | 86 |
| 74 for (int i = 0; i < kFreeCount; i++) { | 87 RegisterList empty_reg_list = allocator()->NewRegisterList(0); |
| 75 int to_free = allocator()->BorrowTemporaryRegister(); | 88 CHECK_EQ(empty_reg_list.first_register().index(), 0); |
| 76 CHECK_EQ(to_free, i); | 89 CHECK_EQ(empty_reg_list.register_count(), 0); |
| 77 } | 90 CHECK_EQ(allocator()->maximum_register_count(), 6); |
| 78 for (int i = 0; i < kFreeCount; i++) { | 91 CHECK_EQ(allocator()->next_register_index(), 3); |
| 79 allocator()->ReturnTemporaryRegister(i); | |
| 80 } | |
| 81 | |
| 82 int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); | |
| 83 CHECK(!allocator()->RegisterIsLive(Register(start))); | |
| 84 for (int i = 0; i < kRunLength; i++) { | |
| 85 CHECK(!allocator()->RegisterIsLive(Register(start + i))); | |
| 86 allocator()->BorrowConsecutiveTemporaryRegister(start + i); | |
| 87 CHECK(allocator()->RegisterIsLive(Register(start + i))); | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingHole) { | |
| 92 static const int kPreAllocatedCount = 7; | |
| 93 static const int kPreAllocatedFreeCount = 6; | |
| 94 static const int kRunLength = 8; | |
| 95 | |
| 96 for (int i = 0; i < kPreAllocatedCount; i++) { | |
| 97 int to_free = allocator()->BorrowTemporaryRegister(); | |
| 98 CHECK_EQ(to_free, i); | |
| 99 } | |
| 100 for (int i = 0; i < kPreAllocatedFreeCount; i++) { | |
| 101 allocator()->ReturnTemporaryRegister(i); | |
| 102 } | |
| 103 int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); | |
| 104 CHECK(!allocator()->RegisterIsLive(Register(start))); | |
| 105 CHECK_EQ(start, kPreAllocatedCount); | |
| 106 for (int i = 0; i < kRunLength; i++) { | |
| 107 CHECK(!allocator()->RegisterIsLive(Register(start + i))); | |
| 108 allocator()->BorrowConsecutiveTemporaryRegister(start + i); | |
| 109 CHECK(allocator()->RegisterIsLive(Register(start + i))); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAvailableInTemporaries) { | |
| 114 static const int kNotRunLength = 13; | |
| 115 static const int kRunLength = 8; | |
| 116 | |
| 117 // Allocate big batch | |
| 118 for (int i = 0; i < kNotRunLength * 2 + kRunLength; i++) { | |
| 119 int allocated = allocator()->BorrowTemporaryRegister(); | |
| 120 CHECK_EQ(allocated, i); | |
| 121 } | |
| 122 // Free every other register either side of target. | |
| 123 for (int i = 0; i < kNotRunLength; i++) { | |
| 124 if ((i & 2) == 1) { | |
| 125 allocator()->ReturnTemporaryRegister(i); | |
| 126 allocator()->ReturnTemporaryRegister(kNotRunLength + kRunLength + i); | |
| 127 } | |
| 128 } | |
| 129 // Free all registers for target. | |
| 130 for (int i = kNotRunLength; i < kNotRunLength + kRunLength; i++) { | |
| 131 allocator()->ReturnTemporaryRegister(i); | |
| 132 } | |
| 133 | |
| 134 int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); | |
| 135 CHECK_EQ(start, kNotRunLength); | |
| 136 for (int i = 0; i < kRunLength; i++) { | |
| 137 CHECK(!allocator()->RegisterIsLive(Register(start + i))); | |
| 138 allocator()->BorrowConsecutiveTemporaryRegister(start + i); | |
| 139 CHECK(allocator()->RegisterIsLive(Register(start + i))); | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 TEST_F(TemporaryRegisterAllocatorTest, NotInRange) { | |
| 144 for (int i = 0; i < 10; i++) { | |
| 145 int reg = allocator()->BorrowTemporaryRegisterNotInRange(2, 5); | |
| 146 CHECK(reg == i || (reg > 2 && reg == i + 4)); | |
| 147 } | |
| 148 for (int i = 0; i < 10; i++) { | |
| 149 if (i < 2) { | |
| 150 allocator()->ReturnTemporaryRegister(i); | |
| 151 } else { | |
| 152 allocator()->ReturnTemporaryRegister(i + 4); | |
| 153 } | |
| 154 } | |
| 155 int reg0 = allocator()->BorrowTemporaryRegisterNotInRange(0, 3); | |
| 156 CHECK_EQ(reg0, 4); | |
| 157 int reg1 = allocator()->BorrowTemporaryRegisterNotInRange(3, 10); | |
| 158 CHECK_EQ(reg1, 2); | |
| 159 int reg2 = allocator()->BorrowTemporaryRegisterNotInRange(2, 6); | |
| 160 CHECK_EQ(reg2, 1); | |
| 161 allocator()->ReturnTemporaryRegister(reg0); | |
| 162 allocator()->ReturnTemporaryRegister(reg1); | |
| 163 allocator()->ReturnTemporaryRegister(reg2); | |
| 164 } | |
| 165 | |
| 166 class BytecodeRegisterAllocatorTest : public TestWithIsolateAndZone { | |
| 167 public: | |
| 168 BytecodeRegisterAllocatorTest() {} | |
| 169 ~BytecodeRegisterAllocatorTest() override {} | |
| 170 }; | |
| 171 | |
| 172 TEST_F(BytecodeRegisterAllocatorTest, TemporariesRecycled) { | |
| 173 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); | |
| 174 | |
| 175 int first; | |
| 176 { | |
| 177 BytecodeRegisterAllocator allocator(zone(), | |
| 178 builder.temporary_register_allocator()); | |
| 179 first = allocator.NewRegister().index(); | |
| 180 allocator.NewRegister(); | |
| 181 allocator.NewRegister(); | |
| 182 allocator.NewRegister(); | |
| 183 } | |
| 184 | |
| 185 int second; | |
| 186 { | |
| 187 BytecodeRegisterAllocator allocator(zone(), | |
| 188 builder.temporary_register_allocator()); | |
| 189 second = allocator.NewRegister().index(); | |
| 190 } | |
| 191 | |
| 192 CHECK_EQ(first, second); | |
| 193 } | |
| 194 | |
| 195 TEST_F(BytecodeRegisterAllocatorTest, ConsecutiveRegisters) { | |
| 196 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); | |
| 197 BytecodeRegisterAllocator allocator(zone(), | |
| 198 builder.temporary_register_allocator()); | |
| 199 allocator.PrepareForConsecutiveAllocations(4); | |
| 200 Register reg0 = allocator.NextConsecutiveRegister(); | |
| 201 Register other = allocator.NewRegister(); | |
| 202 Register reg1 = allocator.NextConsecutiveRegister(); | |
| 203 Register reg2 = allocator.NextConsecutiveRegister(); | |
| 204 Register reg3 = allocator.NextConsecutiveRegister(); | |
| 205 USE(other); | |
| 206 | |
| 207 CHECK(Register::AreContiguous(reg0, reg1, reg2, reg3)); | |
| 208 } | 92 } |
| 209 | 93 |
| 210 } // namespace interpreter | 94 } // namespace interpreter |
| 211 } // namespace internal | 95 } // namespace internal |
| 212 } // namespace v8 | 96 } // namespace v8 |
| OLD | NEW |