| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/interpreter/bytecode-array-builder.h" | 5 #include "src/interpreter/bytecode-array-builder.h" |
| 6 | 6 |
| 7 namespace v8 { | 7 namespace v8 { |
| 8 namespace internal { | 8 namespace internal { |
| 9 namespace interpreter { | 9 namespace interpreter { |
| 10 | 10 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 GetOperand(operand_index)); | 57 GetOperand(operand_index)); |
| 58 } | 58 } |
| 59 | 59 |
| 60 private: | 60 private: |
| 61 const BytecodeArrayBuilder& array_builder_; | 61 const BytecodeArrayBuilder& array_builder_; |
| 62 size_t previous_bytecode_start_; | 62 size_t previous_bytecode_start_; |
| 63 | 63 |
| 64 DISALLOW_COPY_AND_ASSIGN(PreviousBytecodeHelper); | 64 DISALLOW_COPY_AND_ASSIGN(PreviousBytecodeHelper); |
| 65 }; | 65 }; |
| 66 | 66 |
| 67 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) | 67 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone, |
| 68 int parameter_count, |
| 69 int context_count, int locals_count) |
| 68 : isolate_(isolate), | 70 : isolate_(isolate), |
| 69 zone_(zone), | 71 zone_(zone), |
| 70 bytecodes_(zone), | 72 bytecodes_(zone), |
| 71 bytecode_generated_(false), | 73 bytecode_generated_(false), |
| 72 constant_array_builder_(isolate, zone), | 74 constant_array_builder_(isolate, zone), |
| 73 handler_table_builder_(isolate, zone), | 75 handler_table_builder_(isolate, zone), |
| 74 last_block_end_(0), | 76 last_block_end_(0), |
| 75 last_bytecode_start_(~0), | 77 last_bytecode_start_(~0), |
| 76 exit_seen_in_block_(false), | 78 exit_seen_in_block_(false), |
| 77 unbound_jumps_(0), | 79 unbound_jumps_(0), |
| 78 parameter_count_(-1), | 80 parameter_count_(parameter_count), |
| 79 local_register_count_(-1), | 81 local_register_count_(locals_count), |
| 80 context_register_count_(-1), | 82 context_register_count_(context_count), |
| 81 temporary_register_count_(0), | 83 temporary_allocator_(zone, fixed_register_count()), |
| 82 free_temporaries_(zone), | 84 register_translator_(this) { |
| 83 register_translator_(this) {} | 85 DCHECK_GE(parameter_count_, 0); |
| 86 DCHECK_GE(context_register_count_, 0); |
| 87 DCHECK_GE(local_register_count_, 0); |
| 88 } |
| 84 | 89 |
| 85 BytecodeArrayBuilder::~BytecodeArrayBuilder() { DCHECK_EQ(0, unbound_jumps_); } | 90 BytecodeArrayBuilder::~BytecodeArrayBuilder() { DCHECK_EQ(0, unbound_jumps_); } |
| 86 | 91 |
| 87 | |
| 88 void BytecodeArrayBuilder::set_locals_count(int number_of_locals) { | |
| 89 local_register_count_ = number_of_locals; | |
| 90 DCHECK_LE(context_register_count_, 0); | |
| 91 } | |
| 92 | |
| 93 | |
| 94 void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) { | |
| 95 parameter_count_ = number_of_parameters; | |
| 96 } | |
| 97 | |
| 98 | |
| 99 void BytecodeArrayBuilder::set_context_count(int number_of_contexts) { | |
| 100 context_register_count_ = number_of_contexts; | |
| 101 DCHECK_GE(local_register_count_, 0); | |
| 102 } | |
| 103 | |
| 104 | |
| 105 Register BytecodeArrayBuilder::first_context_register() const { | 92 Register BytecodeArrayBuilder::first_context_register() const { |
| 106 DCHECK_GT(context_register_count_, 0); | 93 DCHECK_GT(context_register_count_, 0); |
| 107 return Register(local_register_count_); | 94 return Register(local_register_count_); |
| 108 } | 95 } |
| 109 | 96 |
| 110 | 97 |
| 111 Register BytecodeArrayBuilder::last_context_register() const { | 98 Register BytecodeArrayBuilder::last_context_register() const { |
| 112 DCHECK_GT(context_register_count_, 0); | 99 DCHECK_GT(context_register_count_, 0); |
| 113 return Register(local_register_count_ + context_register_count_ - 1); | 100 return Register(local_register_count_ + context_register_count_ - 1); |
| 114 } | 101 } |
| 115 | 102 |
| 116 | 103 |
| 117 Register BytecodeArrayBuilder::first_temporary_register() const { | |
| 118 DCHECK_GT(temporary_register_count_, 0); | |
| 119 return Register(fixed_register_count()); | |
| 120 } | |
| 121 | |
| 122 | |
| 123 Register BytecodeArrayBuilder::last_temporary_register() const { | |
| 124 DCHECK_GT(temporary_register_count_, 0); | |
| 125 return Register(fixed_register_count() + temporary_register_count_ - 1); | |
| 126 } | |
| 127 | |
| 128 | |
| 129 Register BytecodeArrayBuilder::Parameter(int parameter_index) const { | 104 Register BytecodeArrayBuilder::Parameter(int parameter_index) const { |
| 130 DCHECK_GE(parameter_index, 0); | 105 DCHECK_GE(parameter_index, 0); |
| 131 return Register::FromParameterIndex(parameter_index, parameter_count()); | 106 return Register::FromParameterIndex(parameter_index, parameter_count()); |
| 132 } | 107 } |
| 133 | 108 |
| 134 | 109 |
| 135 bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const { | 110 bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const { |
| 136 return reg.is_parameter() || reg.index() < locals_count(); | 111 return reg.is_parameter() || reg.index() < locals_count(); |
| 137 } | 112 } |
| 138 | 113 |
| 139 | 114 |
| 140 bool BytecodeArrayBuilder::RegisterIsTemporary(Register reg) const { | |
| 141 return temporary_register_count_ > 0 && first_temporary_register() <= reg && | |
| 142 reg <= last_temporary_register(); | |
| 143 } | |
| 144 | |
| 145 | |
| 146 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { | 115 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { |
| 147 DCHECK_EQ(bytecode_generated_, false); | 116 DCHECK_EQ(bytecode_generated_, false); |
| 148 EnsureReturn(); | 117 EnsureReturn(); |
| 149 | 118 |
| 150 int bytecode_size = static_cast<int>(bytecodes_.size()); | 119 int bytecode_size = static_cast<int>(bytecodes_.size()); |
| 151 int register_count = | 120 int register_count = |
| 152 fixed_and_temporary_register_count() + translation_register_count(); | 121 fixed_and_temporary_register_count() + translation_register_count(); |
| 153 int frame_size = register_count * kPointerSize; | 122 int frame_size = register_count * kPointerSize; |
| 154 Handle<FixedArray> constant_pool = constant_array_builder()->ToFixedArray(); | 123 Handle<FixedArray> constant_pool = constant_array_builder()->ToFixedArray(); |
| 155 Handle<FixedArray> handler_table = handler_table_builder()->ToHandlerTable(); | 124 Handle<FixedArray> handler_table = handler_table_builder()->ToHandlerTable(); |
| (...skipping 1045 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1201 BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() { | 1170 BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() { |
| 1202 Output(Bytecode::kDeleteLookupSlot); | 1171 Output(Bytecode::kDeleteLookupSlot); |
| 1203 return *this; | 1172 return *this; |
| 1204 } | 1173 } |
| 1205 | 1174 |
| 1206 | 1175 |
| 1207 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { | 1176 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { |
| 1208 return constant_array_builder()->Insert(object); | 1177 return constant_array_builder()->Insert(object); |
| 1209 } | 1178 } |
| 1210 | 1179 |
| 1211 void BytecodeArrayBuilder::ForgeTemporaryRegister() { | 1180 bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const { |
| 1212 temporary_register_count_++; | 1181 return temporary_register_allocator()->RegisterIsLive(reg); |
| 1213 } | 1182 } |
| 1214 | 1183 |
| 1215 int BytecodeArrayBuilder::BorrowTemporaryRegister() { | |
| 1216 if (free_temporaries_.empty()) { | |
| 1217 ForgeTemporaryRegister(); | |
| 1218 return last_temporary_register().index(); | |
| 1219 } else { | |
| 1220 auto pos = free_temporaries_.begin(); | |
| 1221 int retval = *pos; | |
| 1222 free_temporaries_.erase(pos); | |
| 1223 return retval; | |
| 1224 } | |
| 1225 } | |
| 1226 | |
| 1227 | |
| 1228 int BytecodeArrayBuilder::BorrowTemporaryRegisterNotInRange(int start_index, | |
| 1229 int end_index) { | |
| 1230 auto index = free_temporaries_.lower_bound(start_index); | |
| 1231 if (index == free_temporaries_.begin()) { | |
| 1232 // If start_index is the first free register, check for a register | |
| 1233 // greater than end_index. | |
| 1234 index = free_temporaries_.upper_bound(end_index); | |
| 1235 if (index == free_temporaries_.end()) { | |
| 1236 ForgeTemporaryRegister(); | |
| 1237 return last_temporary_register().index(); | |
| 1238 } | |
| 1239 } else { | |
| 1240 // If there is a free register < start_index | |
| 1241 index--; | |
| 1242 } | |
| 1243 | |
| 1244 int retval = *index; | |
| 1245 free_temporaries_.erase(index); | |
| 1246 return retval; | |
| 1247 } | |
| 1248 | |
| 1249 | |
| 1250 void BytecodeArrayBuilder::BorrowConsecutiveTemporaryRegister(int reg_index) { | |
| 1251 DCHECK(free_temporaries_.find(reg_index) != free_temporaries_.end()); | |
| 1252 free_temporaries_.erase(reg_index); | |
| 1253 } | |
| 1254 | |
| 1255 | |
| 1256 void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) { | |
| 1257 DCHECK(free_temporaries_.find(reg_index) == free_temporaries_.end()); | |
| 1258 free_temporaries_.insert(reg_index); | |
| 1259 } | |
| 1260 | |
| 1261 | |
| 1262 int BytecodeArrayBuilder::PrepareForConsecutiveTemporaryRegisters( | |
| 1263 size_t count) { | |
| 1264 if (count == 0) { | |
| 1265 return -1; | |
| 1266 } | |
| 1267 | |
| 1268 // TODO(oth): replace use of set<> here for free_temporaries with a | |
| 1269 // more efficient structure. And/or partition into two searches - | |
| 1270 // one before the translation window and one after. | |
| 1271 | |
| 1272 // A run will require at least |count| free temporaries. | |
| 1273 while (free_temporaries_.size() < count) { | |
| 1274 ForgeTemporaryRegister(); | |
| 1275 free_temporaries_.insert(last_temporary_register().index()); | |
| 1276 } | |
| 1277 | |
| 1278 // Search within existing temporaries for a run. | |
| 1279 auto start = free_temporaries_.begin(); | |
| 1280 size_t run_length = 0; | |
| 1281 for (auto run_end = start; run_end != free_temporaries_.end(); run_end++) { | |
| 1282 int expected = *start + static_cast<int>(run_length); | |
| 1283 if (*run_end != expected) { | |
| 1284 start = run_end; | |
| 1285 run_length = 0; | |
| 1286 } | |
| 1287 Register reg_start(*start); | |
| 1288 Register reg_expected(expected); | |
| 1289 if (RegisterTranslator::DistanceToTranslationWindow(reg_start) > 0 && | |
| 1290 RegisterTranslator::DistanceToTranslationWindow(reg_expected) <= 0) { | |
| 1291 // Run straddles the lower edge of the translation window. Registers | |
| 1292 // after the start of this boundary are displaced by the register | |
| 1293 // translator to provide a hole for translation. Runs either side | |
| 1294 // of the boundary are fine. | |
| 1295 start = run_end; | |
| 1296 run_length = 0; | |
| 1297 } | |
| 1298 if (++run_length == count) { | |
| 1299 return *start; | |
| 1300 } | |
| 1301 } | |
| 1302 | |
| 1303 // Continue run if possible across existing last temporary. | |
| 1304 if (temporary_register_count_ > 0 && | |
| 1305 (start == free_temporaries_.end() || | |
| 1306 *start + static_cast<int>(run_length) != | |
| 1307 last_temporary_register().index() + 1)) { | |
| 1308 run_length = 0; | |
| 1309 } | |
| 1310 | |
| 1311 // Pad temporaries if extended run would cross translation boundary. | |
| 1312 Register reg_first(*start); | |
| 1313 Register reg_last(*start + static_cast<int>(count) - 1); | |
| 1314 DCHECK_GT(RegisterTranslator::DistanceToTranslationWindow(reg_first), | |
| 1315 RegisterTranslator::DistanceToTranslationWindow(reg_last)); | |
| 1316 while (RegisterTranslator::DistanceToTranslationWindow(reg_first) > 0 && | |
| 1317 RegisterTranslator::DistanceToTranslationWindow(reg_last) <= 0) { | |
| 1318 ForgeTemporaryRegister(); | |
| 1319 free_temporaries_.insert(last_temporary_register().index()); | |
| 1320 start = --free_temporaries_.end(); | |
| 1321 reg_first = Register(*start); | |
| 1322 reg_last = Register(*start + static_cast<int>(count) - 1); | |
| 1323 run_length = 0; | |
| 1324 } | |
| 1325 | |
| 1326 // Ensure enough registers for run. | |
| 1327 while (run_length++ < count) { | |
| 1328 ForgeTemporaryRegister(); | |
| 1329 free_temporaries_.insert(last_temporary_register().index()); | |
| 1330 } | |
| 1331 | |
| 1332 int run_start = | |
| 1333 last_temporary_register().index() - static_cast<int>(count) + 1; | |
| 1334 DCHECK(RegisterTranslator::DistanceToTranslationWindow(Register(run_start)) <= | |
| 1335 0 || | |
| 1336 RegisterTranslator::DistanceToTranslationWindow( | |
| 1337 Register(run_start + static_cast<int>(count) - 1)) > 0); | |
| 1338 return run_start; | |
| 1339 } | |
| 1340 | |
| 1341 | |
| 1342 bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const { | |
| 1343 if (temporary_register_count_ > 0) { | |
| 1344 DCHECK(reg.index() >= first_temporary_register().index() && | |
| 1345 reg.index() <= last_temporary_register().index()); | |
| 1346 return free_temporaries_.find(reg.index()) == free_temporaries_.end(); | |
| 1347 } else { | |
| 1348 return false; | |
| 1349 } | |
| 1350 } | |
| 1351 | |
| 1352 | |
| 1353 bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, | 1184 bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, |
| 1354 uint32_t operand_value) const { | 1185 uint32_t operand_value) const { |
| 1355 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); | 1186 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); |
| 1356 switch (operand_type) { | 1187 switch (operand_type) { |
| 1357 case OperandType::kNone: | 1188 case OperandType::kNone: |
| 1358 return false; | 1189 return false; |
| 1359 case OperandType::kRegCount16: { | 1190 case OperandType::kRegCount16: { |
| 1360 // Expect kRegCount16 is part of a range previous operand is a | 1191 // Expect kRegCount16 is part of a range previous operand is a |
| 1361 // valid operand to start a range. | 1192 // valid operand to start a range. |
| 1362 if (operand_index > 0) { | 1193 if (operand_index > 0) { |
| (...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1813 } | 1644 } |
| 1814 | 1645 |
| 1815 // static | 1646 // static |
| 1816 bool BytecodeArrayBuilder::FitsInReg16OperandUntranslated(Register value) { | 1647 bool BytecodeArrayBuilder::FitsInReg16OperandUntranslated(Register value) { |
| 1817 return value.is_short_operand(); | 1648 return value.is_short_operand(); |
| 1818 } | 1649 } |
| 1819 | 1650 |
| 1820 } // namespace interpreter | 1651 } // namespace interpreter |
| 1821 } // namespace internal | 1652 } // namespace internal |
| 1822 } // namespace v8 | 1653 } // namespace v8 |
| OLD | NEW |