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