Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include "src/interpreter/bytecode-array-writer.h"
6 :
7 : #include "src/api-inl.h"
8 : #include "src/interpreter/bytecode-jump-table.h"
9 : #include "src/interpreter/bytecode-label.h"
10 : #include "src/interpreter/bytecode-node.h"
11 : #include "src/interpreter/bytecode-register.h"
12 : #include "src/interpreter/bytecode-source-info.h"
13 : #include "src/interpreter/constant-array-builder.h"
14 : #include "src/log.h"
15 : #include "src/objects-inl.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 : namespace interpreter {
20 :
21 : STATIC_CONST_MEMBER_DEFINITION const size_t
22 : BytecodeArrayWriter::kMaxSizeOfPackedBytecode;
23 :
24 2107289 : BytecodeArrayWriter::BytecodeArrayWriter(
25 : Zone* zone, ConstantArrayBuilder* constant_array_builder,
26 : SourcePositionTableBuilder::RecordingMode source_position_mode)
27 : : bytecodes_(zone),
28 : unbound_jumps_(0),
29 : source_position_table_builder_(source_position_mode),
30 : constant_array_builder_(constant_array_builder),
31 : last_bytecode_(Bytecode::kIllegal),
32 : last_bytecode_offset_(0),
33 : last_bytecode_had_source_info_(false),
34 : elide_noneffectful_bytecodes_(FLAG_ignition_elide_noneffectful_bytecodes),
35 4214578 : exit_seen_in_block_(false) {
36 2107292 : bytecodes_.reserve(512); // Derived via experimentation.
37 2107291 : }
38 :
39 2082970 : Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
40 2082954 : Isolate* isolate, int register_count, int parameter_count,
41 2082970 : Handle<ByteArray> handler_table) {
42 : DCHECK_EQ(0, unbound_jumps_);
43 :
44 4165940 : int bytecode_size = static_cast<int>(bytecodes()->size());
45 2082970 : int frame_size = register_count * kSystemPointerSize;
46 : Handle<FixedArray> constant_pool =
47 2082970 : constant_array_builder()->ToFixedArray(isolate);
48 : Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray(
49 : bytecode_size, &bytecodes()->front(), frame_size, parameter_count,
50 2082977 : constant_pool);
51 2082975 : bytecode_array->set_handler_table(*handler_table);
52 : // TODO(v8:8510): Need to support native functions that should always have
53 : // source positions suppressed and should write empty_byte_array here.
54 2082978 : if (!source_position_table_builder_.Omit()) {
55 : Handle<ByteArray> source_position_table =
56 2082958 : source_position_table_builder()->ToSourcePositionTable(isolate);
57 4165912 : bytecode_array->set_source_position_table(*source_position_table);
58 2083260 : LOG_CODE_EVENT(isolate, CodeLinePosInfoRecordEvent(
59 : bytecode_array->GetFirstBytecodeAddress(),
60 : *source_position_table));
61 : }
62 2082977 : return bytecode_array;
63 : }
64 :
65 228877530 : void BytecodeArrayWriter::Write(BytecodeNode* node) {
66 : DCHECK(!Bytecodes::IsJump(node->bytecode()));
67 :
68 152884524 : if (exit_seen_in_block_) return; // Don't emit dead code.
69 : UpdateExitSeenInBlock(node->bytecode());
70 228659178 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
71 :
72 76230190 : UpdateSourcePositionTable(node);
73 76234137 : EmitBytecode(node);
74 : }
75 :
76 6189050 : void BytecodeArrayWriter::WriteJump(BytecodeNode* node, BytecodeLabel* label) {
77 : DCHECK(Bytecodes::IsJump(node->bytecode()));
78 :
79 : // TODO(rmcilroy): For forward jumps we could also mark the label as dead,
80 : // thereby avoiding emitting dead code when we bind the label.
81 4140956 : if (exit_seen_in_block_) return; // Don't emit dead code.
82 : UpdateExitSeenInBlock(node->bytecode());
83 6177897 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
84 :
85 2059341 : UpdateSourcePositionTable(node);
86 2059355 : EmitJump(node, label);
87 : }
88 :
89 60036 : void BytecodeArrayWriter::WriteSwitch(BytecodeNode* node,
90 : BytecodeJumpTable* jump_table) {
91 : DCHECK(Bytecodes::IsSwitch(node->bytecode()));
92 :
93 : // TODO(rmcilroy): For jump tables we could also mark the table as dead,
94 : // thereby avoiding emitting dead code when we bind the entries.
95 40516 : if (exit_seen_in_block_) return; // Don't emit dead code.
96 : UpdateExitSeenInBlock(node->bytecode());
97 59667 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
98 :
99 19889 : UpdateSourcePositionTable(node);
100 : EmitSwitch(node, jump_table);
101 : }
102 :
103 2665206 : void BytecodeArrayWriter::BindLabel(BytecodeLabel* label) {
104 2665206 : size_t current_offset = bytecodes()->size();
105 2665206 : if (label->is_forward_target()) {
106 : // An earlier jump instruction refers to this label. Update it's location.
107 1806252 : PatchJump(current_offset, label->offset());
108 : // Now treat as if the label will only be back referred to.
109 : }
110 : label->bind_to(current_offset);
111 : InvalidateLastBytecode();
112 2665194 : exit_seen_in_block_ = false; // Starting a new basic block.
113 2665194 : }
114 :
115 0 : void BytecodeArrayWriter::BindLabel(const BytecodeLabel& target,
116 : BytecodeLabel* label) {
117 : DCHECK(!label->is_bound());
118 : DCHECK(target.is_bound());
119 0 : if (label->is_forward_target()) {
120 : // An earlier jump instruction refers to this label. Update it's location.
121 0 : PatchJump(target.offset(), label->offset());
122 : // Now treat as if the label will only be back referred to.
123 : }
124 : label->bind_to(target.offset());
125 : InvalidateLastBytecode();
126 : // exit_seen_in_block_ was reset when target was bound, so shouldn't be
127 : // changed here.
128 0 : }
129 :
130 140757 : void BytecodeArrayWriter::BindJumpTableEntry(BytecodeJumpTable* jump_table,
131 46919 : int case_value) {
132 : DCHECK(!jump_table->is_bound(case_value));
133 :
134 46919 : size_t current_offset = bytecodes()->size();
135 46919 : size_t relative_jump = current_offset - jump_table->switch_bytecode_offset();
136 :
137 : constant_array_builder()->SetJumpTableSmi(
138 : jump_table->ConstantPoolEntryFor(case_value),
139 93838 : Smi::FromInt(static_cast<int>(relative_jump)));
140 : jump_table->mark_bound(case_value);
141 :
142 : InvalidateLastBytecode();
143 46919 : exit_seen_in_block_ = false; // Starting a new basic block.
144 46919 : }
145 :
146 78308238 : void BytecodeArrayWriter::UpdateSourcePositionTable(
147 : const BytecodeNode* const node) {
148 156616476 : int bytecode_offset = static_cast<int>(bytecodes()->size());
149 109748144 : const BytecodeSourceInfo& source_info = node->source_info();
150 78308238 : if (source_info.is_valid()) {
151 : source_position_table_builder()->AddPosition(
152 : bytecode_offset, SourcePosition(source_info.source_position()),
153 62879812 : source_info.is_statement());
154 : }
155 78308090 : }
156 :
157 0 : void BytecodeArrayWriter::UpdateExitSeenInBlock(Bytecode bytecode) {
158 : switch (bytecode) {
159 : case Bytecode::kReturn:
160 : case Bytecode::kThrow:
161 : case Bytecode::kReThrow:
162 : case Bytecode::kAbort:
163 : case Bytecode::kJump:
164 : case Bytecode::kJumpConstant:
165 : case Bytecode::kSuspendGenerator:
166 2931581 : exit_seen_in_block_ = true;
167 0 : break;
168 : default:
169 : break;
170 : }
171 0 : }
172 :
173 78298554 : void BytecodeArrayWriter::MaybeElideLastBytecode(Bytecode next_bytecode,
174 : bool has_source_info) {
175 156607092 : if (!elide_noneffectful_bytecodes_) return;
176 :
177 : // If the last bytecode loaded the accumulator without any external effect,
178 : // and the next bytecode clobbers this load without reading the accumulator,
179 : // then the previous bytecode can be elided as it has no effect.
180 175157637 : if (Bytecodes::IsAccumulatorLoadWithoutEffects(last_bytecode_) &&
181 78639793 : Bytecodes::GetAccumulatorUse(next_bytecode) == AccumulatorUse::kWrite &&
182 332505 : (!last_bytecode_had_source_info_ || !has_source_info)) {
183 : DCHECK_GT(bytecodes()->size(), last_bytecode_offset_);
184 329568 : bytecodes()->resize(last_bytecode_offset_);
185 : // If the last bytecode had source info we will transfer the source info
186 : // to this bytecode.
187 329568 : has_source_info |= last_bytecode_had_source_info_;
188 : }
189 78308867 : last_bytecode_ = next_bytecode;
190 78308867 : last_bytecode_had_source_info_ = has_source_info;
191 156617734 : last_bytecode_offset_ = bytecodes()->size();
192 : }
193 :
194 0 : void BytecodeArrayWriter::InvalidateLastBytecode() {
195 2712113 : last_bytecode_ = Bytecode::kIllegal;
196 0 : }
197 :
198 156625602 : void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) {
199 : DCHECK_NE(node->bytecode(), Bytecode::kIllegal);
200 :
201 : Bytecode bytecode = node->bytecode();
202 : OperandScale operand_scale = node->operand_scale();
203 :
204 78313991 : if (operand_scale != OperandScale::kSingle) {
205 12119313 : Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale);
206 24238861 : bytecodes()->push_back(Bytecodes::ToByte(prefix));
207 : }
208 156625759 : bytecodes()->push_back(Bytecodes::ToByte(bytecode));
209 :
210 78311611 : const uint32_t* const operands = node->operands();
211 : const int operand_count = node->operand_count();
212 : const OperandSize* operand_sizes =
213 : Bytecodes::GetOperandSizes(bytecode, operand_scale);
214 183840299 : for (int i = 0; i < operand_count; ++i) {
215 105533589 : switch (operand_sizes[i]) {
216 : case OperandSize::kNone:
217 0 : UNREACHABLE();
218 : break;
219 : case OperandSize::kByte:
220 168468461 : bytecodes()->push_back(static_cast<uint8_t>(operands[i]));
221 84231754 : break;
222 : case OperandSize::kShort: {
223 11223213 : uint16_t operand = static_cast<uint16_t>(operands[i]);
224 : const uint8_t* raw_operand = reinterpret_cast<const uint8_t*>(&operand);
225 11223213 : bytecodes()->push_back(raw_operand[0]);
226 11223261 : bytecodes()->push_back(raw_operand[1]);
227 : break;
228 : }
229 : case OperandSize::kQuad: {
230 : const uint8_t* raw_operand =
231 10078252 : reinterpret_cast<const uint8_t*>(&operands[i]);
232 10078252 : bytecodes()->push_back(raw_operand[0]);
233 10078252 : bytecodes()->push_back(raw_operand[1]);
234 10078249 : bytecodes()->push_back(raw_operand[2]);
235 10078250 : bytecodes()->push_back(raw_operand[3]);
236 10078250 : break;
237 : }
238 : }
239 : }
240 78306710 : }
241 :
242 : // static
243 22999 : Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
244 22999 : switch (jump_bytecode) {
245 : case Bytecode::kJump:
246 : return Bytecode::kJumpConstant;
247 : case Bytecode::kJumpIfTrue:
248 8729 : return Bytecode::kJumpIfTrueConstant;
249 : case Bytecode::kJumpIfFalse:
250 3912 : return Bytecode::kJumpIfFalseConstant;
251 : case Bytecode::kJumpIfToBooleanTrue:
252 4981 : return Bytecode::kJumpIfToBooleanTrueConstant;
253 : case Bytecode::kJumpIfToBooleanFalse:
254 104 : return Bytecode::kJumpIfToBooleanFalseConstant;
255 : case Bytecode::kJumpIfNull:
256 209 : return Bytecode::kJumpIfNullConstant;
257 : case Bytecode::kJumpIfNotNull:
258 1 : return Bytecode::kJumpIfNotNullConstant;
259 : case Bytecode::kJumpIfUndefined:
260 355 : return Bytecode::kJumpIfUndefinedConstant;
261 : case Bytecode::kJumpIfNotUndefined:
262 11 : return Bytecode::kJumpIfNotUndefinedConstant;
263 : case Bytecode::kJumpIfJSReceiver:
264 1 : return Bytecode::kJumpIfJSReceiverConstant;
265 : default:
266 0 : UNREACHABLE();
267 : }
268 : }
269 :
270 1790274 : void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location,
271 1790274 : int delta) {
272 1790274 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
273 : DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
274 : DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
275 : DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
276 : DCHECK_GT(delta, 0);
277 1790274 : size_t operand_location = jump_location + 1;
278 : DCHECK_EQ(bytecodes()->at(operand_location), k8BitJumpPlaceholder);
279 3580548 : if (Bytecodes::ScaleForUnsignedOperand(delta) == OperandScale::kSingle) {
280 : // The jump fits within the range of an UImm8 operand, so cancel
281 : // the reservation and jump directly.
282 1767282 : constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
283 1767305 : bytecodes()->at(operand_location) = static_cast<uint8_t>(delta);
284 : } else {
285 : // The jump does not fit within the range of an UImm8 operand, so
286 : // commit reservation putting the offset into the constant pool,
287 : // and update the jump instruction and operand.
288 : size_t entry = constant_array_builder()->CommitReservedEntry(
289 22992 : OperandSize::kByte, Smi::FromInt(delta));
290 : DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)),
291 : OperandSize::kByte);
292 22994 : jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
293 22994 : bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
294 22994 : bytecodes()->at(operand_location) = static_cast<uint8_t>(entry);
295 : }
296 1790299 : }
297 :
298 15948 : void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location,
299 15948 : int delta) {
300 15948 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
301 : DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
302 : DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
303 : DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
304 : DCHECK_GT(delta, 0);
305 15948 : size_t operand_location = jump_location + 1;
306 : uint8_t operand_bytes[2];
307 31896 : if (Bytecodes::ScaleForUnsignedOperand(delta) <= OperandScale::kDouble) {
308 : // The jump fits within the range of an Imm16 operand, so cancel
309 : // the reservation and jump directly.
310 15943 : constant_array_builder()->DiscardReservedEntry(OperandSize::kShort);
311 : WriteUnalignedUInt16(reinterpret_cast<Address>(operand_bytes),
312 15943 : static_cast<uint16_t>(delta));
313 : } else {
314 : // The jump does not fit within the range of an Imm16 operand, so
315 : // commit reservation putting the offset into the constant pool,
316 : // and update the jump instruction and operand.
317 : size_t entry = constant_array_builder()->CommitReservedEntry(
318 5 : OperandSize::kShort, Smi::FromInt(delta));
319 5 : jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
320 5 : bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
321 : WriteUnalignedUInt16(reinterpret_cast<Address>(operand_bytes),
322 5 : static_cast<uint16_t>(entry));
323 : }
324 : DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
325 : bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder);
326 31896 : bytecodes()->at(operand_location++) = operand_bytes[0];
327 15948 : bytecodes()->at(operand_location) = operand_bytes[1];
328 15948 : }
329 :
330 5 : void BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location,
331 5 : int delta) {
332 : DCHECK(Bytecodes::IsJumpImmediate(
333 : Bytecodes::FromByte(bytecodes()->at(jump_location))));
334 5 : constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad);
335 : uint8_t operand_bytes[4];
336 : WriteUnalignedUInt32(reinterpret_cast<Address>(operand_bytes),
337 5 : static_cast<uint32_t>(delta));
338 5 : size_t operand_location = jump_location + 1;
339 : DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
340 : bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder &&
341 : bytecodes()->at(operand_location + 2) == k8BitJumpPlaceholder &&
342 : bytecodes()->at(operand_location + 3) == k8BitJumpPlaceholder);
343 10 : bytecodes()->at(operand_location++) = operand_bytes[0];
344 10 : bytecodes()->at(operand_location++) = operand_bytes[1];
345 10 : bytecodes()->at(operand_location++) = operand_bytes[2];
346 5 : bytecodes()->at(operand_location) = operand_bytes[3];
347 5 : }
348 :
349 1806233 : void BytecodeArrayWriter::PatchJump(size_t jump_target, size_t jump_location) {
350 1806233 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
351 1806233 : int delta = static_cast<int>(jump_target - jump_location);
352 : int prefix_offset = 0;
353 : OperandScale operand_scale = OperandScale::kSingle;
354 1806233 : if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) {
355 : // If a prefix scaling bytecode is emitted the target offset is one
356 : // less than the case of no prefix scaling bytecode.
357 15953 : delta -= 1;
358 : prefix_offset = 1;
359 15953 : operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode);
360 : jump_bytecode =
361 15953 : Bytecodes::FromByte(bytecodes()->at(jump_location + prefix_offset));
362 : }
363 :
364 : DCHECK(Bytecodes::IsJump(jump_bytecode));
365 1806233 : switch (operand_scale) {
366 : case OperandScale::kSingle:
367 1790280 : PatchJumpWith8BitOperand(jump_location, delta);
368 1790299 : break;
369 : case OperandScale::kDouble:
370 15948 : PatchJumpWith16BitOperand(jump_location + prefix_offset, delta);
371 15948 : break;
372 : case OperandScale::kQuadruple:
373 5 : PatchJumpWith32BitOperand(jump_location + prefix_offset, delta);
374 5 : break;
375 : default:
376 0 : UNREACHABLE();
377 : }
378 1806252 : unbound_jumps_--;
379 1806252 : }
380 :
381 6177969 : void BytecodeArrayWriter::EmitJump(BytecodeNode* node, BytecodeLabel* label) {
382 : DCHECK(Bytecodes::IsJump(node->bytecode()));
383 : DCHECK_EQ(0u, node->operand(0));
384 :
385 2059323 : size_t current_offset = bytecodes()->size();
386 :
387 2059323 : if (label->is_bound()) {
388 253077 : CHECK_GE(current_offset, label->offset());
389 253077 : CHECK_LE(current_offset, static_cast<size_t>(kMaxUInt32));
390 : // Label has been bound already so this is a backwards jump.
391 253077 : uint32_t delta = static_cast<uint32_t>(current_offset - label->offset());
392 : OperandScale operand_scale = Bytecodes::ScaleForUnsignedOperand(delta);
393 253077 : if (operand_scale > OperandScale::kSingle) {
394 : // Adjust for scaling byte prefix for wide jump offset.
395 8160 : delta += 1;
396 : }
397 : DCHECK_EQ(Bytecode::kJumpLoop, node->bytecode());
398 253077 : node->update_operand0(delta);
399 : } else {
400 : // The label has not yet been bound so this is a forward reference
401 : // that will be patched when the label is bound. We create a
402 : // reservation in the constant pool so the jump can be patched
403 : // when the label is bound. The reservation means the maximum size
404 : // of the operand for the constant is known and the jump can
405 : // be emitted into the bytecode stream with space for the operand.
406 1806246 : unbound_jumps_++;
407 : label->set_referrer(current_offset);
408 : OperandSize reserved_operand_size =
409 1806246 : constant_array_builder()->CreateReservedEntry();
410 : DCHECK_NE(Bytecode::kJumpLoop, node->bytecode());
411 1806246 : switch (reserved_operand_size) {
412 : case OperandSize::kNone:
413 0 : UNREACHABLE();
414 : break;
415 : case OperandSize::kByte:
416 1790308 : node->update_operand0(k8BitJumpPlaceholder);
417 1790331 : break;
418 : case OperandSize::kShort:
419 15948 : node->update_operand0(k16BitJumpPlaceholder);
420 15948 : break;
421 : case OperandSize::kQuad:
422 5 : node->update_operand0(k32BitJumpPlaceholder);
423 5 : break;
424 : }
425 : }
426 2059346 : EmitBytecode(node);
427 2059350 : }
428 :
429 19889 : void BytecodeArrayWriter::EmitSwitch(BytecodeNode* node,
430 : BytecodeJumpTable* jump_table) {
431 : DCHECK(Bytecodes::IsSwitch(node->bytecode()));
432 :
433 19889 : size_t current_offset = bytecodes()->size();
434 19889 : if (node->operand_scale() > OperandScale::kSingle) {
435 : // Adjust for scaling byte prefix.
436 122 : current_offset += 1;
437 : }
438 : jump_table->set_switch_bytecode_offset(current_offset);
439 :
440 19889 : EmitBytecode(node);
441 0 : }
442 :
443 : } // namespace interpreter
444 : } // namespace internal
445 178779 : } // namespace v8
|