| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/factory.h" | 7 #include "src/factory.h" |
| 8 #include "src/interpreter/bytecode-label.h" | 8 #include "src/interpreter/bytecode-label.h" |
| 9 #include "src/interpreter/bytecode-register-optimizer.h" | 9 #include "src/interpreter/bytecode-register-optimizer.h" |
| 10 #include "src/objects-inl.h" | 10 #include "src/objects-inl.h" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 | 55 |
| 56 private: | 56 private: |
| 57 BytecodeRegisterAllocator* register_allocator_; | 57 BytecodeRegisterAllocator* register_allocator_; |
| 58 BytecodeRegisterOptimizer* register_optimizer_; | 58 BytecodeRegisterOptimizer* register_optimizer_; |
| 59 | 59 |
| 60 std::vector<BytecodeNode> output_; | 60 std::vector<BytecodeNode> output_; |
| 61 }; | 61 }; |
| 62 | 62 |
| 63 // Sanity tests. | 63 // Sanity tests. |
| 64 | 64 |
| 65 TEST_F(BytecodeRegisterOptimizerTest, WriteNop) { | 65 TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForFlush) { |
| 66 Initialize(1, 1); | 66 Initialize(1, 1); |
| 67 BytecodeNode node(Bytecode::kNop); | 67 Register temp = NewTemporary(); |
| 68 optimizer()->Write(&node); | 68 optimizer()->DoStar(temp, BytecodeSourceInfo()); |
| 69 CHECK_EQ(write_count(), 0); |
| 70 optimizer()->Flush(); |
| 69 CHECK_EQ(write_count(), 1); | 71 CHECK_EQ(write_count(), 1); |
| 70 CHECK_EQ(node, last_written()); | 72 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); |
| 71 } | 73 CHECK_EQ(output()->at(0).operand(0), temp.ToOperand()); |
| 72 | |
| 73 TEST_F(BytecodeRegisterOptimizerTest, WriteNopExpression) { | |
| 74 Initialize(1, 1); | |
| 75 BytecodeSourceInfo source_info(3, false); | |
| 76 BytecodeNode node(Bytecode::kNop, &source_info); | |
| 77 optimizer()->Write(&node); | |
| 78 CHECK_EQ(write_count(), 1); | |
| 79 CHECK_EQ(node, last_written()); | |
| 80 } | |
| 81 | |
| 82 TEST_F(BytecodeRegisterOptimizerTest, WriteNopStatement) { | |
| 83 Initialize(1, 1); | |
| 84 BytecodeSourceInfo source_info(3, true); | |
| 85 BytecodeNode node(Bytecode::kNop); | |
| 86 optimizer()->Write(&node); | |
| 87 CHECK_EQ(write_count(), 1); | |
| 88 CHECK_EQ(node, last_written()); | |
| 89 } | 74 } |
| 90 | 75 |
| 91 TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForJump) { | 76 TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForJump) { |
| 92 Initialize(1, 1); | 77 Initialize(1, 1); |
| 93 Register temp = NewTemporary(); | 78 Register temp = NewTemporary(); |
| 94 BytecodeNode node(Bytecode::kStar, temp.ToOperand()); | 79 optimizer()->DoStar(temp, BytecodeSourceInfo()); |
| 95 optimizer()->Write(&node); | |
| 96 CHECK_EQ(write_count(), 0); | 80 CHECK_EQ(write_count(), 0); |
| 97 BytecodeLabel label; | 81 optimizer()->PrepareForBytecode(Bytecode::kJump); |
| 98 BytecodeNode jump(Bytecode::kJump, 0, nullptr); | |
| 99 optimizer()->WriteJump(&jump, &label); | |
| 100 CHECK_EQ(write_count(), 2); | |
| 101 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); | |
| 102 CHECK_EQ(output()->at(0).operand(0), temp.ToOperand()); | |
| 103 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kJump); | |
| 104 } | |
| 105 | |
| 106 TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForBind) { | |
| 107 Initialize(1, 1); | |
| 108 Register temp = NewTemporary(); | |
| 109 BytecodeNode node(Bytecode::kStar, temp.ToOperand()); | |
| 110 optimizer()->Write(&node); | |
| 111 CHECK_EQ(write_count(), 0); | |
| 112 BytecodeLabel label; | |
| 113 optimizer()->BindLabel(&label); | |
| 114 CHECK_EQ(write_count(), 1); | 82 CHECK_EQ(write_count(), 1); |
| 115 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); | 83 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); |
| 116 CHECK_EQ(output()->at(0).operand(0), temp.ToOperand()); | 84 CHECK_EQ(output()->at(0).operand(0), temp.ToOperand()); |
| 117 } | 85 } |
| 118 | 86 |
| 119 // Basic Register Optimizations | 87 // Basic Register Optimizations |
| 120 | 88 |
| 121 TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { | 89 TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { |
| 122 Initialize(3, 1); | 90 Initialize(3, 1); |
| 123 Register parameter = Register::FromParameterIndex(1, 3); | 91 Register parameter = Register::FromParameterIndex(1, 3); |
| 124 BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand()); | 92 optimizer()->DoLdar(parameter, BytecodeSourceInfo()); |
| 125 optimizer()->Write(&node0); | |
| 126 CHECK_EQ(write_count(), 0); | 93 CHECK_EQ(write_count(), 0); |
| 127 Register temp = NewTemporary(); | 94 Register temp = NewTemporary(); |
| 95 optimizer()->DoStar(temp, BytecodeSourceInfo()); |
| 128 BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand()); | 96 BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand()); |
| 129 optimizer()->Write(&node1); | |
| 130 CHECK_EQ(write_count(), 0); | |
| 131 ReleaseTemporaries(temp); | 97 ReleaseTemporaries(temp); |
| 132 CHECK_EQ(write_count(), 0); | 98 CHECK_EQ(write_count(), 0); |
| 133 BytecodeNode node2(Bytecode::kReturn); | 99 optimizer()->PrepareForBytecode(Bytecode::kReturn); |
| 134 optimizer()->Write(&node2); | |
| 135 CHECK_EQ(write_count(), 2); | |
| 136 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdar); | 100 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdar); |
| 137 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); | 101 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); |
| 138 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kReturn); | |
| 139 } | 102 } |
| 140 | 103 |
| 141 TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterUsed) { | 104 TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterUsed) { |
| 142 Initialize(3, 1); | 105 Initialize(3, 1); |
| 143 BytecodeNode node0(Bytecode::kLdaSmi, 3); | 106 optimizer()->PrepareForBytecode(Bytecode::kLdaSmi); |
| 144 optimizer()->Write(&node0); | |
| 145 CHECK_EQ(write_count(), 1); | |
| 146 Register temp0 = NewTemporary(); | 107 Register temp0 = NewTemporary(); |
| 147 Register temp1 = NewTemporary(); | 108 Register temp1 = NewTemporary(); |
| 148 BytecodeNode node1(Bytecode::kStar, temp1.ToOperand()); | 109 optimizer()->DoStar(temp1, BytecodeSourceInfo()); |
| 149 optimizer()->Write(&node1); | 110 CHECK_EQ(write_count(), 0); |
| 111 optimizer()->PrepareForBytecode(Bytecode::kLdaSmi); |
| 150 CHECK_EQ(write_count(), 1); | 112 CHECK_EQ(write_count(), 1); |
| 151 BytecodeNode node2(Bytecode::kLdaSmi, 1); | 113 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); |
| 152 optimizer()->Write(&node2); | 114 CHECK_EQ(output()->at(0).operand(0), temp1.ToOperand()); |
| 153 CHECK_EQ(write_count(), 3); | 115 optimizer()->DoMov(temp1, temp0, BytecodeSourceInfo()); |
| 154 BytecodeNode node3(Bytecode::kMov, temp1.ToOperand(), temp0.ToOperand()); | 116 CHECK_EQ(write_count(), 1); |
| 155 optimizer()->Write(&node3); | |
| 156 CHECK_EQ(write_count(), 3); | |
| 157 ReleaseTemporaries(temp1); | 117 ReleaseTemporaries(temp1); |
| 158 CHECK_EQ(write_count(), 3); | 118 CHECK_EQ(write_count(), 1); |
| 159 BytecodeNode node4(Bytecode::kLdar, temp0.ToOperand()); | 119 optimizer()->DoLdar(temp0, BytecodeSourceInfo()); |
| 160 optimizer()->Write(&node4); | 120 CHECK_EQ(write_count(), 1); |
| 161 CHECK_EQ(write_count(), 3); | 121 optimizer()->PrepareForBytecode(Bytecode::kReturn); |
| 162 BytecodeNode node5(Bytecode::kReturn); | 122 CHECK_EQ(write_count(), 2); |
| 163 optimizer()->Write(&node5); | 123 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kLdar); |
| 164 CHECK_EQ(write_count(), 5); | 124 CHECK_EQ(output()->at(1).operand(0), temp1.ToOperand()); |
| 165 CHECK_EQ(output()->at(3).bytecode(), Bytecode::kLdar); | |
| 166 CHECK_EQ(output()->at(3).operand(0), temp1.ToOperand()); | |
| 167 CHECK_EQ(output()->at(4).bytecode(), Bytecode::kReturn); | |
| 168 } | 125 } |
| 169 | 126 |
| 170 TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterNotFlushed) { | 127 TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterNotFlushed) { |
| 171 Initialize(3, 1); | 128 Initialize(3, 1); |
| 172 BytecodeNode node0(Bytecode::kLdaSmi, 3); | 129 optimizer()->PrepareForBytecode(Bytecode::kLdaSmi); |
| 173 optimizer()->Write(&node0); | |
| 174 CHECK_EQ(write_count(), 1); | |
| 175 Register temp0 = NewTemporary(); | 130 Register temp0 = NewTemporary(); |
| 176 Register temp1 = NewTemporary(); | 131 Register temp1 = NewTemporary(); |
| 177 BytecodeNode node1(Bytecode::kStar, temp0.ToOperand()); | 132 optimizer()->DoStar(temp0, BytecodeSourceInfo()); |
| 178 optimizer()->Write(&node1); | 133 CHECK_EQ(write_count(), 0); |
| 134 optimizer()->DoStar(temp1, BytecodeSourceInfo()); |
| 135 CHECK_EQ(write_count(), 0); |
| 136 ReleaseTemporaries(temp1); |
| 137 optimizer()->Flush(); |
| 179 CHECK_EQ(write_count(), 1); | 138 CHECK_EQ(write_count(), 1); |
| 180 BytecodeNode node2(Bytecode::kStar, temp1.ToOperand()); | 139 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); |
| 181 optimizer()->Write(&node2); | 140 CHECK_EQ(output()->at(0).operand(0), temp0.ToOperand()); |
| 182 CHECK_EQ(write_count(), 1); | |
| 183 ReleaseTemporaries(temp1); | |
| 184 BytecodeLabel label; | |
| 185 BytecodeNode jump(Bytecode::kJump, 0, nullptr); | |
| 186 optimizer()->WriteJump(&jump, &label); | |
| 187 BytecodeNode node3(Bytecode::kReturn); | |
| 188 optimizer()->Write(&node3); | |
| 189 CHECK_EQ(write_count(), 4); | |
| 190 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kStar); | |
| 191 CHECK_EQ(output()->at(1).operand(0), temp0.ToOperand()); | |
| 192 CHECK_EQ(output()->at(2).bytecode(), Bytecode::kJump); | |
| 193 CHECK_EQ(output()->at(3).bytecode(), Bytecode::kReturn); | |
| 194 } | 141 } |
| 195 | 142 |
| 196 TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) { | 143 TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) { |
| 197 Initialize(3, 1); | 144 Initialize(3, 1); |
| 198 Register parameter = Register::FromParameterIndex(1, 3); | 145 Register parameter = Register::FromParameterIndex(1, 3); |
| 199 BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand()); | 146 optimizer()->DoLdar(parameter, BytecodeSourceInfo()); |
| 200 optimizer()->Write(&node0); | |
| 201 CHECK_EQ(write_count(), 0); | 147 CHECK_EQ(write_count(), 0); |
| 202 Register local = Register(0); | 148 Register local = Register(0); |
| 203 BytecodeNode node1(Bytecode::kStar, local.ToOperand()); | 149 optimizer()->DoStar(local, BytecodeSourceInfo()); |
| 204 optimizer()->Write(&node1); | |
| 205 CHECK_EQ(write_count(), 1); | 150 CHECK_EQ(write_count(), 1); |
| 206 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kMov); | 151 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kMov); |
| 207 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); | 152 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); |
| 208 CHECK_EQ(output()->at(0).operand(1), local.ToOperand()); | 153 CHECK_EQ(output()->at(0).operand(1), local.ToOperand()); |
| 209 | 154 |
| 210 BytecodeNode node2(Bytecode::kReturn); | 155 optimizer()->PrepareForBytecode(Bytecode::kReturn); |
| 211 optimizer()->Write(&node2); | 156 CHECK_EQ(write_count(), 2); |
| 212 CHECK_EQ(write_count(), 3); | |
| 213 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kLdar); | 157 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kLdar); |
| 214 CHECK_EQ(output()->at(1).operand(0), local.ToOperand()); | 158 CHECK_EQ(output()->at(1).operand(0), local.ToOperand()); |
| 215 CHECK_EQ(output()->at(2).bytecode(), Bytecode::kReturn); | |
| 216 } | 159 } |
| 217 | 160 |
| 218 TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotMaterializedForInput) { | 161 TEST_F(BytecodeRegisterOptimizerTest, SingleTemporaryNotMaterializedForInput) { |
| 219 Initialize(3, 1); | 162 Initialize(3, 1); |
| 220 Register parameter = Register::FromParameterIndex(1, 3); | 163 Register parameter = Register::FromParameterIndex(1, 3); |
| 221 Register temp0 = NewTemporary(); | 164 Register temp0 = NewTemporary(); |
| 222 Register temp1 = NewTemporary(); | 165 Register temp1 = NewTemporary(); |
| 223 BytecodeNode node0(Bytecode::kMov, parameter.ToOperand(), temp0.ToOperand()); | 166 optimizer()->DoMov(parameter, temp0, BytecodeSourceInfo()); |
| 224 optimizer()->Write(&node0); | 167 optimizer()->DoMov(parameter, temp1, BytecodeSourceInfo()); |
| 225 BytecodeNode node1(Bytecode::kMov, parameter.ToOperand(), temp1.ToOperand()); | |
| 226 optimizer()->Write(&node1); | |
| 227 CHECK_EQ(write_count(), 0); | 168 CHECK_EQ(write_count(), 0); |
| 228 BytecodeNode node2(Bytecode::kCallJSRuntime, 0, temp0.ToOperand(), 1); | 169 |
| 229 optimizer()->Write(&node2); | 170 Register reg = optimizer()->GetInputRegister(temp0); |
| 230 CHECK_EQ(write_count(), 1); | 171 RegisterList reg_list = |
| 231 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kCallJSRuntime); | 172 optimizer()->GetInputRegisterList(RegisterList(temp0.index(), 1)); |
| 232 CHECK_EQ(output()->at(0).operand(0), 0); | 173 CHECK_EQ(write_count(), 0); |
| 233 CHECK_EQ(output()->at(0).operand(1), parameter.ToOperand()); | 174 CHECK_EQ(parameter.index(), reg.index()); |
| 234 CHECK_EQ(output()->at(0).operand(2), 1); | 175 CHECK_EQ(parameter.index(), reg_list.first_register().index()); |
| 176 CHECK_EQ(1, reg_list.register_count()); |
| 235 } | 177 } |
| 236 | 178 |
| 237 TEST_F(BytecodeRegisterOptimizerTest, RangeOfTemporariesMaterializedForInput) { | 179 TEST_F(BytecodeRegisterOptimizerTest, RangeOfTemporariesMaterializedForInput) { |
| 238 Initialize(3, 1); | 180 Initialize(3, 1); |
| 239 Register parameter = Register::FromParameterIndex(1, 3); | 181 Register parameter = Register::FromParameterIndex(1, 3); |
| 240 Register temp0 = NewTemporary(); | 182 Register temp0 = NewTemporary(); |
| 241 Register temp1 = NewTemporary(); | 183 Register temp1 = NewTemporary(); |
| 242 BytecodeNode node0(Bytecode::kLdaSmi, 3); | 184 optimizer()->PrepareForBytecode(Bytecode::kLdaSmi); |
| 243 optimizer()->Write(&node0); | 185 optimizer()->DoStar(temp0, BytecodeSourceInfo()); |
| 244 CHECK_EQ(write_count(), 1); | 186 optimizer()->DoMov(parameter, temp1, BytecodeSourceInfo()); |
| 245 BytecodeNode node1(Bytecode::kStar, temp0.ToOperand()); | 187 CHECK_EQ(write_count(), 0); |
| 246 optimizer()->Write(&node1); | |
| 247 BytecodeNode node2(Bytecode::kMov, parameter.ToOperand(), temp1.ToOperand()); | |
| 248 optimizer()->Write(&node2); | |
| 249 CHECK_EQ(write_count(), 1); | |
| 250 BytecodeNode node3(Bytecode::kCallJSRuntime, 0, temp0.ToOperand(), 2); | |
| 251 optimizer()->Write(&node3); | |
| 252 CHECK_EQ(write_count(), 4); | |
| 253 | 188 |
| 254 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdaSmi); | 189 optimizer()->PrepareForBytecode(Bytecode::kCallJSRuntime); |
| 255 CHECK_EQ(output()->at(0).operand(0), 3); | 190 RegisterList reg_list = |
| 256 | 191 optimizer()->GetInputRegisterList(RegisterList(temp0.index(), 2)); |
| 257 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kStar); | 192 CHECK_EQ(temp0.index(), reg_list.first_register().index()); |
| 258 CHECK_EQ(output()->at(1).operand(0), temp0.ToOperand()); | 193 CHECK_EQ(2, reg_list.register_count()); |
| 259 | 194 CHECK_EQ(write_count(), 2); |
| 260 CHECK_EQ(output()->at(2).bytecode(), Bytecode::kMov); | 195 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); |
| 261 CHECK_EQ(output()->at(2).operand(0), parameter.ToOperand()); | 196 CHECK_EQ(output()->at(0).operand(0), temp0.ToOperand()); |
| 262 CHECK_EQ(output()->at(2).operand(1), temp1.ToOperand()); | 197 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kMov); |
| 263 | 198 CHECK_EQ(output()->at(1).operand(0), parameter.ToOperand()); |
| 264 CHECK_EQ(output()->at(3).bytecode(), Bytecode::kCallJSRuntime); | 199 CHECK_EQ(output()->at(1).operand(1), temp1.ToOperand()); |
| 265 CHECK_EQ(output()->at(3).operand(0), 0); | |
| 266 CHECK_EQ(output()->at(3).operand(1), temp0.ToOperand()); | |
| 267 CHECK_EQ(output()->at(3).operand(2), 2); | |
| 268 } | 200 } |
| 269 | 201 |
| 270 } // namespace interpreter | 202 } // namespace interpreter |
| 271 } // namespace internal | 203 } // namespace internal |
| 272 } // namespace v8 | 204 } // namespace v8 |
| OLD | NEW |