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 { |
| 16 public: |
| 17 TemporaryRegisterAllocatorTest() : allocator_(zone(), 0) {} |
| 18 ~TemporaryRegisterAllocatorTest() override {} |
| 19 TemporaryRegisterAllocator* allocator() { return &allocator_; } |
| 20 |
| 21 private: |
| 22 TemporaryRegisterAllocator allocator_; |
| 23 }; |
| 24 |
| 25 TEST_F(TemporaryRegisterAllocatorTest, FirstAllocation) { |
| 26 CHECK_EQ(allocator()->allocation_count(), 0); |
| 27 int reg0_index = allocator()->BorrowTemporaryRegister(); |
| 28 CHECK_EQ(reg0_index, 0); |
| 29 CHECK_EQ(allocator()->allocation_count(), 1); |
| 30 CHECK(allocator()->RegisterIsLive(Register(reg0_index))); |
| 31 allocator()->ReturnTemporaryRegister(reg0_index); |
| 32 CHECK(!allocator()->RegisterIsLive(Register(reg0_index))); |
| 33 CHECK_EQ(allocator()->allocation_count(), 1); |
| 34 CHECK(allocator()->first_temporary_register() == Register(0)); |
| 35 CHECK(allocator()->last_temporary_register() == Register(0)); |
| 36 } |
| 37 |
| 38 TEST_F(TemporaryRegisterAllocatorTest, SimpleAllocations) { |
| 39 for (int i = 0; i < 13; i++) { |
| 40 int reg_index = allocator()->BorrowTemporaryRegister(); |
| 41 CHECK_EQ(reg_index, i); |
| 42 CHECK_EQ(allocator()->allocation_count(), i + 1); |
| 43 } |
| 44 for (int i = 0; i < 13; i++) { |
| 45 CHECK(allocator()->RegisterIsLive(Register(i))); |
| 46 allocator()->ReturnTemporaryRegister(i); |
| 47 CHECK(!allocator()->RegisterIsLive(Register(i))); |
| 48 int reg_index = allocator()->BorrowTemporaryRegister(); |
| 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 |
| 59 TEST_F(TemporaryRegisterAllocatorTest, SimpleRangeAllocation) { |
| 60 static const int kRunLength = 7; |
| 61 int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); |
| 62 CHECK(!allocator()->RegisterIsLive(Register(start))); |
| 63 for (int i = 0; i < kRunLength; i++) { |
| 64 CHECK(!allocator()->RegisterIsLive(Register(start + i))); |
| 65 allocator()->BorrowConsecutiveTemporaryRegister(start + i); |
| 66 CHECK(allocator()->RegisterIsLive(Register(start + i))); |
| 67 } |
| 68 } |
| 69 |
| 70 TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingFree) { |
| 71 static const int kFreeCount = 3; |
| 72 static const int kRunLength = 6; |
| 73 |
| 74 for (int i = 0; i < kFreeCount; i++) { |
| 75 int to_free = allocator()->BorrowTemporaryRegister(); |
| 76 CHECK_EQ(to_free, i); |
| 77 } |
| 78 for (int i = 0; i < kFreeCount; i++) { |
| 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, RangeAvoidsTranslationBoundary) { |
| 144 int boundary = RegisterTranslator::DistanceToTranslationWindow(Register(0)); |
| 145 int limit = boundary + 64; |
| 146 |
| 147 for (int run_length = 2; run_length < 32; run_length += 7) { |
| 148 ZoneVector<int> run_starts(zone()); |
| 149 for (int start = 0; start < limit; start += run_length) { |
| 150 int run_start = |
| 151 allocator()->PrepareForConsecutiveTemporaryRegisters(run_length); |
| 152 run_starts.push_back(run_start); |
| 153 for (int i = 0; i < run_length; i++) { |
| 154 allocator()->BorrowConsecutiveTemporaryRegister(run_start + i); |
| 155 } |
| 156 CHECK(run_start >= boundary || run_start + run_length <= boundary); |
| 157 } |
| 158 for (size_t batch = 0; batch < run_starts.size(); batch++) { |
| 159 for (int i = run_starts[batch]; i < run_starts[batch] + run_length; i++) { |
| 160 allocator()->ReturnTemporaryRegister(i); |
| 161 } |
| 162 } |
| 163 } |
| 164 } |
| 165 |
| 166 TEST_F(TemporaryRegisterAllocatorTest, NotInRange) { |
| 167 for (int i = 0; i < 10; i++) { |
| 168 int reg = allocator()->BorrowTemporaryRegisterNotInRange(2, 5); |
| 169 CHECK(reg == i || (reg > 2 && reg == i + 4)); |
| 170 } |
| 171 for (int i = 0; i < 10; i++) { |
| 172 if (i < 2) { |
| 173 allocator()->ReturnTemporaryRegister(i); |
| 174 } else { |
| 175 allocator()->ReturnTemporaryRegister(i + 4); |
| 176 } |
| 177 } |
| 178 int reg0 = allocator()->BorrowTemporaryRegisterNotInRange(0, 3); |
| 179 CHECK_EQ(reg0, 4); |
| 180 int reg1 = allocator()->BorrowTemporaryRegisterNotInRange(3, 10); |
| 181 CHECK_EQ(reg1, 2); |
| 182 int reg2 = allocator()->BorrowTemporaryRegisterNotInRange(2, 6); |
| 183 CHECK_EQ(reg2, 1); |
| 184 allocator()->ReturnTemporaryRegister(reg0); |
| 185 allocator()->ReturnTemporaryRegister(reg1); |
| 186 allocator()->ReturnTemporaryRegister(reg2); |
| 187 } |
| 188 |
15 class BytecodeRegisterAllocatorTest : public TestWithIsolateAndZone { | 189 class BytecodeRegisterAllocatorTest : public TestWithIsolateAndZone { |
16 public: | 190 public: |
17 BytecodeRegisterAllocatorTest() {} | 191 BytecodeRegisterAllocatorTest() {} |
18 ~BytecodeRegisterAllocatorTest() override {} | 192 ~BytecodeRegisterAllocatorTest() override {} |
19 }; | 193 }; |
20 | 194 |
21 | |
22 TEST_F(BytecodeRegisterAllocatorTest, TemporariesRecycled) { | 195 TEST_F(BytecodeRegisterAllocatorTest, TemporariesRecycled) { |
23 BytecodeArrayBuilder builder(isolate(), zone()); | 196 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); |
24 builder.set_parameter_count(0); | |
25 builder.set_locals_count(0); | |
26 builder.set_context_count(0); | |
27 | 197 |
28 int first; | 198 int first; |
29 { | 199 { |
30 BytecodeRegisterAllocator temporaries(&builder); | 200 BytecodeRegisterAllocator allocator(zone(), |
31 first = temporaries.NewRegister().index(); | 201 builder.temporary_register_allocator()); |
32 temporaries.NewRegister(); | 202 first = allocator.NewRegister().index(); |
33 temporaries.NewRegister(); | 203 allocator.NewRegister(); |
34 temporaries.NewRegister(); | 204 allocator.NewRegister(); |
| 205 allocator.NewRegister(); |
35 } | 206 } |
36 | 207 |
37 int second; | 208 int second; |
38 { | 209 { |
39 BytecodeRegisterAllocator temporaries(&builder); | 210 BytecodeRegisterAllocator allocator(zone(), |
40 second = temporaries.NewRegister().index(); | 211 builder.temporary_register_allocator()); |
| 212 second = allocator.NewRegister().index(); |
41 } | 213 } |
42 | 214 |
43 CHECK_EQ(first, second); | 215 CHECK_EQ(first, second); |
44 } | 216 } |
45 | 217 |
46 | |
47 TEST_F(BytecodeRegisterAllocatorTest, ConsecutiveRegisters) { | 218 TEST_F(BytecodeRegisterAllocatorTest, ConsecutiveRegisters) { |
48 BytecodeArrayBuilder builder(isolate(), zone()); | 219 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); |
49 builder.set_parameter_count(0); | 220 BytecodeRegisterAllocator allocator(zone(), |
50 builder.set_locals_count(0); | 221 builder.temporary_register_allocator()); |
51 builder.set_context_count(0); | 222 allocator.PrepareForConsecutiveAllocations(4); |
52 | 223 Register reg0 = allocator.NextConsecutiveRegister(); |
53 BytecodeRegisterAllocator temporaries(&builder); | 224 Register other = allocator.NewRegister(); |
54 temporaries.PrepareForConsecutiveAllocations(4); | 225 Register reg1 = allocator.NextConsecutiveRegister(); |
55 Register reg0 = temporaries.NextConsecutiveRegister(); | 226 Register reg2 = allocator.NextConsecutiveRegister(); |
56 Register other = temporaries.NewRegister(); | 227 Register reg3 = allocator.NextConsecutiveRegister(); |
57 Register reg1 = temporaries.NextConsecutiveRegister(); | |
58 Register reg2 = temporaries.NextConsecutiveRegister(); | |
59 Register reg3 = temporaries.NextConsecutiveRegister(); | |
60 USE(other); | 228 USE(other); |
61 | 229 |
62 CHECK(Register::AreContiguous(reg0, reg1, reg2, reg3)); | 230 CHECK(Register::AreContiguous(reg0, reg1, reg2, reg3)); |
63 } | 231 } |
64 | 232 |
65 } // namespace interpreter | 233 } // namespace interpreter |
66 } // namespace internal | 234 } // namespace internal |
67 } // namespace v8 | 235 } // namespace v8 |
OLD | NEW |