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 |