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-writer.h" | 5 #include "src/interpreter/bytecode-array-writer.h" |
6 | 6 |
7 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/interpreter/bytecode-label.h" | 8 #include "src/interpreter/bytecode-label.h" |
9 #include "src/interpreter/bytecode-register.h" | 9 #include "src/interpreter/bytecode-register.h" |
10 #include "src/interpreter/constant-array-builder.h" | 10 #include "src/interpreter/constant-array-builder.h" |
11 #include "src/log.h" | 11 #include "src/log.h" |
12 | 12 |
13 namespace v8 { | 13 namespace v8 { |
14 namespace internal { | 14 namespace internal { |
15 namespace interpreter { | 15 namespace interpreter { |
16 | 16 |
17 STATIC_CONST_MEMBER_DEFINITION const size_t | 17 STATIC_CONST_MEMBER_DEFINITION const size_t |
18 BytecodeArrayWriter::kMaxSizeOfPackedBytecode; | 18 BytecodeArrayWriter::kMaxSizeOfPackedBytecode; |
19 | 19 |
20 BytecodeArrayWriter::BytecodeArrayWriter( | 20 BytecodeArrayWriter::BytecodeArrayWriter( |
21 Zone* zone, ConstantArrayBuilder* constant_array_builder, | 21 Zone* zone, ConstantArrayBuilder* constant_array_builder, |
22 SourcePositionTableBuilder::RecordingMode source_position_mode) | 22 SourcePositionTableBuilder::RecordingMode source_position_mode) |
23 : bytecodes_(zone), | 23 : bytecodes_(zone), |
| 24 max_register_count_(0), |
24 unbound_jumps_(0), | 25 unbound_jumps_(0), |
25 source_position_table_builder_(zone, source_position_mode), | 26 source_position_table_builder_(zone, source_position_mode), |
26 constant_array_builder_(constant_array_builder) { | 27 constant_array_builder_(constant_array_builder) {} |
27 bytecodes_.reserve(512); // Derived via experimentation. | |
28 } | |
29 | 28 |
30 // override | 29 // override |
31 BytecodeArrayWriter::~BytecodeArrayWriter() {} | 30 BytecodeArrayWriter::~BytecodeArrayWriter() {} |
32 | 31 |
33 // override | 32 // override |
34 Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray( | 33 Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray( |
35 Isolate* isolate, int register_count, int parameter_count, | 34 Isolate* isolate, int fixed_register_count, int parameter_count, |
36 Handle<FixedArray> handler_table) { | 35 Handle<FixedArray> handler_table) { |
37 DCHECK_EQ(0, unbound_jumps_); | 36 DCHECK_EQ(0, unbound_jumps_); |
38 | 37 |
39 int bytecode_size = static_cast<int>(bytecodes()->size()); | 38 int bytecode_size = static_cast<int>(bytecodes()->size()); |
40 int frame_size = register_count * kPointerSize; | 39 |
| 40 // All locals need a frame slot for the debugger, but may not be |
| 41 // present in generated code. |
| 42 int frame_size_for_locals = fixed_register_count * kPointerSize; |
| 43 int frame_size_used = max_register_count() * kPointerSize; |
| 44 int frame_size = std::max(frame_size_for_locals, frame_size_used); |
41 Handle<FixedArray> constant_pool = | 45 Handle<FixedArray> constant_pool = |
42 constant_array_builder()->ToFixedArray(isolate); | 46 constant_array_builder()->ToFixedArray(isolate); |
43 Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray( | 47 Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray( |
44 bytecode_size, &bytecodes()->front(), frame_size, parameter_count, | 48 bytecode_size, &bytecodes()->front(), frame_size, parameter_count, |
45 constant_pool); | 49 constant_pool); |
46 bytecode_array->set_handler_table(*handler_table); | 50 bytecode_array->set_handler_table(*handler_table); |
47 Handle<ByteArray> source_position_table = | 51 Handle<ByteArray> source_position_table = |
48 source_position_table_builder()->ToSourcePositionTable( | 52 source_position_table_builder()->ToSourcePositionTable( |
49 isolate, Handle<AbstractCode>::cast(bytecode_array)); | 53 isolate, Handle<AbstractCode>::cast(bytecode_array)); |
50 bytecode_array->set_source_position_table(*source_position_table); | 54 bytecode_array->set_source_position_table(*source_position_table); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 const BytecodeNode* const node) { | 97 const BytecodeNode* const node) { |
94 int bytecode_offset = static_cast<int>(bytecodes()->size()); | 98 int bytecode_offset = static_cast<int>(bytecodes()->size()); |
95 const BytecodeSourceInfo& source_info = node->source_info(); | 99 const BytecodeSourceInfo& source_info = node->source_info(); |
96 if (source_info.is_valid()) { | 100 if (source_info.is_valid()) { |
97 source_position_table_builder()->AddPosition(bytecode_offset, | 101 source_position_table_builder()->AddPosition(bytecode_offset, |
98 source_info.source_position(), | 102 source_info.source_position(), |
99 source_info.is_statement()); | 103 source_info.is_statement()); |
100 } | 104 } |
101 } | 105 } |
102 | 106 |
| 107 namespace { |
| 108 |
| 109 OperandScale ScaleForScalableByteOperand(OperandSize operand_size) { |
| 110 STATIC_ASSERT(static_cast<int>(OperandSize::kByte) == |
| 111 static_cast<int>(OperandScale::kSingle)); |
| 112 STATIC_ASSERT(static_cast<int>(OperandSize::kShort) == |
| 113 static_cast<int>(OperandScale::kDouble)); |
| 114 STATIC_ASSERT(static_cast<int>(OperandSize::kQuad) == |
| 115 static_cast<int>(OperandScale::kQuadruple)); |
| 116 return static_cast<OperandScale>(operand_size); |
| 117 } |
| 118 |
| 119 OperandScale OperandScaleForScalableSignedByte(uint32_t operand_value) { |
| 120 int32_t signed_operand = static_cast<int32_t>(operand_value); |
| 121 OperandSize bytes_required = Bytecodes::SizeForSignedOperand(signed_operand); |
| 122 return ScaleForScalableByteOperand(bytes_required); |
| 123 } |
| 124 |
| 125 OperandScale OperandScaleForScalableUnsignedByte(uint32_t operand_value) { |
| 126 OperandSize bytes_required = Bytecodes::SizeForUnsignedOperand(operand_value); |
| 127 return ScaleForScalableByteOperand(bytes_required); |
| 128 } |
| 129 |
| 130 OperandScale GetOperandScale(const BytecodeNode* const node) { |
| 131 const OperandTypeInfo* operand_type_infos = |
| 132 Bytecodes::GetOperandTypeInfos(node->bytecode()); |
| 133 OperandScale operand_scale = OperandScale::kSingle; |
| 134 int operand_count = node->operand_count(); |
| 135 for (int i = 0; i < operand_count; ++i) { |
| 136 switch (operand_type_infos[i]) { |
| 137 case OperandTypeInfo::kScalableSignedByte: { |
| 138 uint32_t operand = node->operand(i); |
| 139 operand_scale = |
| 140 std::max(operand_scale, OperandScaleForScalableSignedByte(operand)); |
| 141 break; |
| 142 } |
| 143 case OperandTypeInfo::kScalableUnsignedByte: { |
| 144 uint32_t operand = node->operand(i); |
| 145 operand_scale = std::max(operand_scale, |
| 146 OperandScaleForScalableUnsignedByte(operand)); |
| 147 break; |
| 148 } |
| 149 case OperandTypeInfo::kFixedUnsignedByte: |
| 150 case OperandTypeInfo::kFixedUnsignedShort: |
| 151 break; |
| 152 case OperandTypeInfo::kNone: |
| 153 UNREACHABLE(); |
| 154 break; |
| 155 } |
| 156 } |
| 157 return operand_scale; |
| 158 } |
| 159 |
| 160 } // namespace |
| 161 |
103 void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) { | 162 void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) { |
104 DCHECK_NE(node->bytecode(), Bytecode::kIllegal); | 163 DCHECK_NE(node->bytecode(), Bytecode::kIllegal); |
105 | 164 |
106 Bytecode bytecode = node->bytecode(); | 165 uint8_t buffer[kMaxSizeOfPackedBytecode]; |
107 OperandScale operand_scale = node->operand_scale(); | 166 uint8_t* buffer_limit = buffer; |
108 | 167 |
| 168 OperandScale operand_scale = GetOperandScale(node); |
109 if (operand_scale != OperandScale::kSingle) { | 169 if (operand_scale != OperandScale::kSingle) { |
110 Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale); | 170 Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale); |
111 bytecodes()->push_back(Bytecodes::ToByte(prefix)); | 171 *buffer_limit++ = Bytecodes::ToByte(prefix); |
112 } | 172 } |
113 bytecodes()->push_back(Bytecodes::ToByte(bytecode)); | 173 |
| 174 Bytecode bytecode = node->bytecode(); |
| 175 *buffer_limit++ = Bytecodes::ToByte(bytecode); |
114 | 176 |
115 const uint32_t* const operands = node->operands(); | 177 const uint32_t* const operands = node->operands(); |
116 const int operand_count = node->operand_count(); | 178 const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); |
117 const OperandSize* operand_sizes = | 179 const int operand_count = Bytecodes::NumberOfOperands(bytecode); |
118 Bytecodes::GetOperandSizes(bytecode, operand_scale); | |
119 for (int i = 0; i < operand_count; ++i) { | 180 for (int i = 0; i < operand_count; ++i) { |
120 switch (operand_sizes[i]) { | 181 OperandSize operand_size = |
| 182 Bytecodes::SizeOfOperand(operand_types[i], operand_scale); |
| 183 switch (operand_size) { |
121 case OperandSize::kNone: | 184 case OperandSize::kNone: |
122 UNREACHABLE(); | 185 UNREACHABLE(); |
123 break; | 186 break; |
124 case OperandSize::kByte: | 187 case OperandSize::kByte: |
125 bytecodes()->push_back(static_cast<uint8_t>(operands[i])); | 188 *buffer_limit++ = static_cast<uint8_t>(operands[i]); |
126 break; | 189 break; |
127 case OperandSize::kShort: { | 190 case OperandSize::kShort: { |
128 const uint8_t* raw_operand = | 191 WriteUnalignedUInt16(buffer_limit, operands[i]); |
129 reinterpret_cast<const uint8_t*>(&operands[i]); | 192 buffer_limit += 2; |
130 bytecodes()->push_back(raw_operand[0]); | |
131 bytecodes()->push_back(raw_operand[1]); | |
132 break; | 193 break; |
133 } | 194 } |
134 case OperandSize::kQuad: { | 195 case OperandSize::kQuad: { |
135 const uint8_t* raw_operand = | 196 WriteUnalignedUInt32(buffer_limit, operands[i]); |
136 reinterpret_cast<const uint8_t*>(&operands[i]); | 197 buffer_limit += 4; |
137 bytecodes()->push_back(raw_operand[0]); | |
138 bytecodes()->push_back(raw_operand[1]); | |
139 bytecodes()->push_back(raw_operand[2]); | |
140 bytecodes()->push_back(raw_operand[3]); | |
141 break; | 198 break; |
142 } | 199 } |
143 } | 200 } |
| 201 |
| 202 int count = Bytecodes::GetNumberOfRegistersRepresentedBy(operand_types[i]); |
| 203 if (count == 0) { |
| 204 continue; |
| 205 } |
| 206 // NB operand_types is terminated by OperandType::kNone so |
| 207 // operand_types[i + 1] is valid whilst i < operand_count. |
| 208 if (operand_types[i + 1] == OperandType::kRegCount) { |
| 209 count = static_cast<int>(operands[i]); |
| 210 } |
| 211 Register reg = Register::FromOperand(static_cast<int32_t>(operands[i])); |
| 212 max_register_count_ = std::max(max_register_count_, reg.index() + count); |
144 } | 213 } |
| 214 |
| 215 DCHECK_LE(buffer_limit, buffer + sizeof(buffer)); |
| 216 bytecodes()->insert(bytecodes()->end(), buffer, buffer_limit); |
145 } | 217 } |
146 | 218 |
147 // static | 219 // static |
148 Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) { | 220 Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) { |
149 switch (jump_bytecode) { | 221 switch (jump_bytecode) { |
150 case Bytecode::kJump: | 222 case Bytecode::kJump: |
151 return Bytecode::kJumpConstant; | 223 return Bytecode::kJumpConstant; |
152 case Bytecode::kJumpIfTrue: | 224 case Bytecode::kJumpIfTrue: |
153 return Bytecode::kJumpIfTrueConstant; | 225 return Bytecode::kJumpIfTrueConstant; |
154 case Bytecode::kJumpIfFalse: | 226 case Bytecode::kJumpIfFalse: |
(...skipping 13 matching lines...) Expand all Loading... |
168 return Bytecode::kIllegal; | 240 return Bytecode::kIllegal; |
169 } | 241 } |
170 } | 242 } |
171 | 243 |
172 void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location, | 244 void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location, |
173 int delta) { | 245 int delta) { |
174 Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location)); | 246 Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location)); |
175 DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); | 247 DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); |
176 size_t operand_location = jump_location + 1; | 248 size_t operand_location = jump_location + 1; |
177 DCHECK_EQ(bytecodes()->at(operand_location), k8BitJumpPlaceholder); | 249 DCHECK_EQ(bytecodes()->at(operand_location), k8BitJumpPlaceholder); |
178 if (Bytecodes::ScaleForSignedOperand(delta) == OperandScale::kSingle) { | 250 if (Bytecodes::SizeForSignedOperand(delta) == OperandSize::kByte) { |
179 // The jump fits within the range of an Imm8 operand, so cancel | 251 // The jump fits within the range of an Imm operand, so cancel |
180 // the reservation and jump directly. | 252 // the reservation and jump directly. |
181 constant_array_builder()->DiscardReservedEntry(OperandSize::kByte); | 253 constant_array_builder()->DiscardReservedEntry(OperandSize::kByte); |
182 bytecodes()->at(operand_location) = static_cast<uint8_t>(delta); | 254 bytecodes()->at(operand_location) = static_cast<uint8_t>(delta); |
183 } else { | 255 } else { |
184 // The jump does not fit within the range of an Imm8 operand, so | 256 // The jump does not fit within the range of an Imm operand, so |
185 // commit reservation putting the offset into the constant pool, | 257 // commit reservation putting the offset into the constant pool, |
186 // and update the jump instruction and operand. | 258 // and update the jump instruction and operand. |
187 size_t entry = constant_array_builder()->CommitReservedEntry( | 259 size_t entry = constant_array_builder()->CommitReservedEntry( |
188 OperandSize::kByte, Smi::FromInt(delta)); | 260 OperandSize::kByte, Smi::FromInt(delta)); |
| 261 DCHECK_LE(entry, kMaxUInt32); |
189 DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)), | 262 DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)), |
190 OperandSize::kByte); | 263 OperandSize::kByte); |
191 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); | 264 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); |
192 bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode); | 265 bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode); |
193 bytecodes()->at(operand_location) = static_cast<uint8_t>(entry); | 266 bytecodes()->at(operand_location) = static_cast<uint8_t>(entry); |
194 } | 267 } |
195 } | 268 } |
196 | 269 |
197 void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location, | 270 void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location, |
198 int delta) { | 271 int delta) { |
199 Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location)); | 272 Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location)); |
200 DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); | 273 DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); |
201 size_t operand_location = jump_location + 1; | 274 size_t operand_location = jump_location + 1; |
202 uint8_t operand_bytes[2]; | 275 uint8_t operand_bytes[2]; |
203 if (Bytecodes::ScaleForSignedOperand(delta) <= OperandScale::kDouble) { | 276 if (Bytecodes::SizeForSignedOperand(delta) <= OperandSize::kShort) { |
204 // The jump fits within the range of an Imm16 operand, so cancel | |
205 // the reservation and jump directly. | |
206 constant_array_builder()->DiscardReservedEntry(OperandSize::kShort); | 277 constant_array_builder()->DiscardReservedEntry(OperandSize::kShort); |
207 WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(delta)); | 278 WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(delta)); |
208 } else { | 279 } else { |
209 // The jump does not fit within the range of an Imm16 operand, so | 280 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); |
210 // commit reservation putting the offset into the constant pool, | 281 bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode); |
211 // and update the jump instruction and operand. | |
212 size_t entry = constant_array_builder()->CommitReservedEntry( | 282 size_t entry = constant_array_builder()->CommitReservedEntry( |
213 OperandSize::kShort, Smi::FromInt(delta)); | 283 OperandSize::kShort, Smi::FromInt(delta)); |
214 DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)), | |
215 OperandSize::kShort); | |
216 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); | |
217 bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode); | |
218 WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry)); | 284 WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry)); |
219 } | 285 } |
220 DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder && | 286 DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder && |
221 bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder); | 287 bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder); |
222 bytecodes()->at(operand_location++) = operand_bytes[0]; | 288 bytecodes()->at(operand_location++) = operand_bytes[0]; |
223 bytecodes()->at(operand_location) = operand_bytes[1]; | 289 bytecodes()->at(operand_location) = operand_bytes[1]; |
224 } | 290 } |
225 | 291 |
226 void BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location, | 292 void BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location, |
227 int delta) { | 293 int delta) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 DCHECK_EQ(0, node->operand(0)); | 344 DCHECK_EQ(0, node->operand(0)); |
279 | 345 |
280 size_t current_offset = bytecodes()->size(); | 346 size_t current_offset = bytecodes()->size(); |
281 | 347 |
282 if (label->is_bound()) { | 348 if (label->is_bound()) { |
283 CHECK_GE(current_offset, label->offset()); | 349 CHECK_GE(current_offset, label->offset()); |
284 CHECK_LE(current_offset, static_cast<size_t>(kMaxInt)); | 350 CHECK_LE(current_offset, static_cast<size_t>(kMaxInt)); |
285 // Label has been bound already so this is a backwards jump. | 351 // Label has been bound already so this is a backwards jump. |
286 size_t abs_delta = current_offset - label->offset(); | 352 size_t abs_delta = current_offset - label->offset(); |
287 int delta = -static_cast<int>(abs_delta); | 353 int delta = -static_cast<int>(abs_delta); |
288 OperandScale operand_scale = Bytecodes::ScaleForSignedOperand(delta); | 354 OperandSize operand_size = Bytecodes::SizeForSignedOperand(delta); |
289 if (operand_scale > OperandScale::kSingle) { | 355 if (operand_size > OperandSize::kByte) { |
290 // Adjust for scaling byte prefix for wide jump offset. | 356 // Adjust for scaling byte prefix for wide jump offset. |
291 DCHECK_LE(delta, 0); | 357 DCHECK_LE(delta, 0); |
292 delta -= 1; | 358 delta -= 1; |
293 } | 359 } |
294 DCHECK_EQ(Bytecode::kJumpLoop, node->bytecode()); | 360 DCHECK_EQ(Bytecode::kJumpLoop, node->bytecode()); |
295 node->set_bytecode(node->bytecode(), delta, node->operand(1)); | 361 node->set_bytecode(node->bytecode(), delta, node->operand(1)); |
296 } else { | 362 } else { |
297 // The label has not yet been bound so this is a forward reference | 363 // The label has not yet been bound so this is a forward reference |
298 // that will be patched when the label is bound. We create a | 364 // that will be patched when the label is bound. We create a |
299 // reservation in the constant pool so the jump can be patched | 365 // reservation in the constant pool so the jump can be patched |
(...skipping 19 matching lines...) Expand all Loading... |
319 node->set_bytecode(node->bytecode(), k32BitJumpPlaceholder); | 385 node->set_bytecode(node->bytecode(), k32BitJumpPlaceholder); |
320 break; | 386 break; |
321 } | 387 } |
322 } | 388 } |
323 EmitBytecode(node); | 389 EmitBytecode(node); |
324 } | 390 } |
325 | 391 |
326 } // namespace interpreter | 392 } // namespace interpreter |
327 } // namespace internal | 393 } // namespace internal |
328 } // namespace v8 | 394 } // namespace v8 |
OLD | NEW |