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.h"
8 : #include "src/interpreter/bytecode-label.h"
9 : #include "src/interpreter/bytecode-node.h"
10 : #include "src/interpreter/bytecode-register.h"
11 : #include "src/interpreter/bytecode-source-info.h"
12 : #include "src/interpreter/constant-array-builder.h"
13 : #include "src/log.h"
14 : #include "src/objects-inl.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 : namespace interpreter {
19 :
20 : STATIC_CONST_MEMBER_DEFINITION const size_t
21 : BytecodeArrayWriter::kMaxSizeOfPackedBytecode;
22 :
23 2104905 : BytecodeArrayWriter::BytecodeArrayWriter(
24 : Zone* zone, ConstantArrayBuilder* constant_array_builder,
25 : SourcePositionTableBuilder::RecordingMode source_position_mode)
26 : : bytecodes_(zone),
27 : unbound_jumps_(0),
28 : source_position_table_builder_(zone, source_position_mode),
29 : constant_array_builder_(constant_array_builder),
30 : last_bytecode_(Bytecode::kIllegal),
31 : last_bytecode_offset_(0),
32 : last_bytecode_had_source_info_(false),
33 : elide_noneffectful_bytecodes_(FLAG_ignition_elide_noneffectful_bytecodes),
34 4209810 : exit_seen_in_block_(false) {
35 2104905 : bytecodes_.reserve(512); // Derived via experimentation.
36 2104911 : }
37 :
38 2103817 : Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
39 : Isolate* isolate, int register_count, int parameter_count,
40 2103817 : Handle<FixedArray> handler_table) {
41 : DCHECK_EQ(0, unbound_jumps_);
42 :
43 4207634 : int bytecode_size = static_cast<int>(bytecodes()->size());
44 2103817 : int frame_size = register_count * kPointerSize;
45 : Handle<FixedArray> constant_pool =
46 2103817 : constant_array_builder()->ToFixedArray(isolate);
47 : Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray(
48 : bytecode_size, &bytecodes()->front(), frame_size, parameter_count,
49 2103823 : constant_pool);
50 2103825 : bytecode_array->set_handler_table(*handler_table);
51 : Handle<ByteArray> source_position_table =
52 : source_position_table_builder()->ToSourcePositionTable(
53 2103820 : isolate, Handle<AbstractCode>::cast(bytecode_array));
54 2103822 : bytecode_array->set_source_position_table(*source_position_table);
55 2103825 : return bytecode_array;
56 : }
57 :
58 139358676 : void BytecodeArrayWriter::Write(BytecodeNode* node) {
59 : DCHECK(!Bytecodes::IsJump(node->bytecode()));
60 :
61 139410838 : if (exit_seen_in_block_) return; // Don't emit dead code.
62 : UpdateExitSeenInBlock(node->bytecode());
63 139306486 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
64 :
65 69653348 : UpdateSourcePositionTable(node);
66 69653334 : EmitBytecode(node);
67 : }
68 :
69 6153842 : void BytecodeArrayWriter::WriteJump(BytecodeNode* node, BytecodeLabel* label) {
70 : DCHECK(Bytecodes::IsJump(node->bytecode()));
71 :
72 : // TODO(rmcilroy): For forward jumps we could also mark the label as dead,
73 : // thereby avoiding emitting dead code when we bind the label.
74 6168918 : if (exit_seen_in_block_) return; // Don't emit dead code.
75 : UpdateExitSeenInBlock(node->bytecode());
76 6138764 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
77 :
78 3069382 : UpdateSourcePositionTable(node);
79 3069382 : EmitJump(node, label);
80 : }
81 :
82 4749872 : void BytecodeArrayWriter::BindLabel(BytecodeLabel* label) {
83 4749872 : size_t current_offset = bytecodes()->size();
84 4749872 : if (label->is_forward_target()) {
85 : // An earlier jump instruction refers to this label. Update it's location.
86 2877991 : PatchJump(current_offset, label->offset());
87 : // Now treat as if the label will only be back referred to.
88 : }
89 : label->bind_to(current_offset);
90 : InvalidateLastBytecode();
91 4749872 : exit_seen_in_block_ = false; // Starting a new basic block.
92 4749872 : }
93 :
94 0 : void BytecodeArrayWriter::BindLabel(const BytecodeLabel& target,
95 : BytecodeLabel* label) {
96 : DCHECK(!label->is_bound());
97 : DCHECK(target.is_bound());
98 0 : if (label->is_forward_target()) {
99 : // An earlier jump instruction refers to this label. Update it's location.
100 0 : PatchJump(target.offset(), label->offset());
101 : // Now treat as if the label will only be back referred to.
102 : }
103 : label->bind_to(target.offset());
104 : InvalidateLastBytecode();
105 : // exit_seen_in_block_ was reset when target was bound, so shouldn't be
106 : // changed here.
107 0 : }
108 :
109 72722691 : void BytecodeArrayWriter::UpdateSourcePositionTable(
110 : const BytecodeNode* const node) {
111 145445382 : int bytecode_offset = static_cast<int>(bytecodes()->size());
112 100302691 : const BytecodeSourceInfo& source_info = node->source_info();
113 72722691 : if (source_info.is_valid()) {
114 : source_position_table_builder()->AddPosition(
115 : bytecode_offset, SourcePosition(source_info.source_position()),
116 55160000 : source_info.is_statement());
117 : }
118 72722685 : }
119 :
120 0 : void BytecodeArrayWriter::UpdateExitSeenInBlock(Bytecode bytecode) {
121 : switch (bytecode) {
122 : case Bytecode::kReturn:
123 : case Bytecode::kThrow:
124 : case Bytecode::kReThrow:
125 : case Bytecode::kJump:
126 : case Bytecode::kJumpConstant:
127 3543362 : exit_seen_in_block_ = true;
128 0 : break;
129 : default:
130 : break;
131 : }
132 0 : }
133 :
134 72722589 : void BytecodeArrayWriter::MaybeElideLastBytecode(Bytecode next_bytecode,
135 : bool has_source_info) {
136 145445274 : if (!elide_noneffectful_bytecodes_) return;
137 :
138 : // If the last bytecode loaded the accumulator without any external effect,
139 : // and the next bytecode clobbers this load without reading the accumulator,
140 : // then the previous bytecode can be elided as it has no effect.
141 162779939 : if (Bytecodes::IsAccumulatorLoadWithoutEffects(last_bytecode_) &&
142 73308631 : Bytecodes::GetAccumulatorUse(next_bytecode) == AccumulatorUse::kWrite &&
143 587492 : (!last_bytecode_had_source_info_ || !has_source_info)) {
144 : DCHECK_GT(bytecodes()->size(), last_bytecode_offset_);
145 584702 : bytecodes()->resize(last_bytecode_offset_);
146 : // If the last bytecode had source info we will transfer the source info
147 : // to this bytecode.
148 584702 : has_source_info |= last_bytecode_had_source_info_;
149 : }
150 72722648 : last_bytecode_ = next_bytecode;
151 72722648 : last_bytecode_had_source_info_ = has_source_info;
152 145445296 : last_bytecode_offset_ = bytecodes()->size();
153 : }
154 :
155 0 : void BytecodeArrayWriter::InvalidateLastBytecode() {
156 4749872 : last_bytecode_ = Bytecode::kIllegal;
157 0 : }
158 :
159 145445229 : void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) {
160 : DCHECK_NE(node->bytecode(), Bytecode::kIllegal);
161 :
162 : Bytecode bytecode = node->bytecode();
163 : OperandScale operand_scale = node->operand_scale();
164 :
165 72722627 : if (operand_scale != OperandScale::kSingle) {
166 11174064 : Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale);
167 22348128 : bytecodes()->push_back(Bytecodes::ToByte(prefix));
168 : }
169 145445229 : bytecodes()->push_back(Bytecodes::ToByte(bytecode));
170 :
171 72722602 : const uint32_t* const operands = node->operands();
172 : const int operand_count = node->operand_count();
173 : const OperandSize* operand_sizes =
174 : Bytecodes::GetOperandSizes(bytecode, operand_scale);
175 176283678 : for (int i = 0; i < operand_count; ++i) {
176 103561160 : switch (operand_sizes[i]) {
177 : case OperandSize::kNone:
178 4 : UNREACHABLE();
179 : break;
180 : case OperandSize::kByte:
181 170139341 : bytecodes()->push_back(static_cast<uint8_t>(operands[i]));
182 85069631 : break;
183 : case OperandSize::kShort: {
184 18296616 : uint16_t operand = static_cast<uint16_t>(operands[i]);
185 : const uint8_t* raw_operand = reinterpret_cast<const uint8_t*>(&operand);
186 18296616 : bytecodes()->push_back(raw_operand[0]);
187 18296616 : bytecodes()->push_back(raw_operand[1]);
188 : break;
189 : }
190 : case OperandSize::kQuad: {
191 : const uint8_t* raw_operand =
192 194944 : reinterpret_cast<const uint8_t*>(&operands[i]);
193 194944 : bytecodes()->push_back(raw_operand[0]);
194 194944 : bytecodes()->push_back(raw_operand[1]);
195 194944 : bytecodes()->push_back(raw_operand[2]);
196 194944 : bytecodes()->push_back(raw_operand[3]);
197 194944 : break;
198 : }
199 : }
200 : }
201 72722518 : }
202 :
203 : // static
204 82763 : Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
205 82763 : switch (jump_bytecode) {
206 : case Bytecode::kJump:
207 : return Bytecode::kJumpConstant;
208 : case Bytecode::kJumpIfTrue:
209 25557 : return Bytecode::kJumpIfTrueConstant;
210 : case Bytecode::kJumpIfFalse:
211 5479 : return Bytecode::kJumpIfFalseConstant;
212 : case Bytecode::kJumpIfToBooleanTrue:
213 7382 : return Bytecode::kJumpIfToBooleanTrueConstant;
214 : case Bytecode::kJumpIfToBooleanFalse:
215 1111 : return Bytecode::kJumpIfToBooleanFalseConstant;
216 : case Bytecode::kJumpIfNotHole:
217 1 : return Bytecode::kJumpIfNotHoleConstant;
218 : case Bytecode::kJumpIfNull:
219 208 : return Bytecode::kJumpIfNullConstant;
220 : case Bytecode::kJumpIfNotNull:
221 1 : return Bytecode::kJumpIfNotNullConstant;
222 : case Bytecode::kJumpIfUndefined:
223 484 : return Bytecode::kJumpIfUndefinedConstant;
224 : case Bytecode::kJumpIfNotUndefined:
225 31 : return Bytecode::kJumpIfNotUndefinedConstant;
226 : case Bytecode::kJumpIfJSReceiver:
227 1 : return Bytecode::kJumpIfJSReceiverConstant;
228 : default:
229 0 : UNREACHABLE();
230 : return Bytecode::kIllegal;
231 : }
232 : }
233 :
234 2794851 : void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location,
235 2794851 : int delta) {
236 2794851 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
237 : DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
238 : DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
239 : DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
240 : DCHECK_GT(delta, 0);
241 2794851 : size_t operand_location = jump_location + 1;
242 : DCHECK_EQ(bytecodes()->at(operand_location), k8BitJumpPlaceholder);
243 5589702 : if (Bytecodes::ScaleForUnsignedOperand(delta) == OperandScale::kSingle) {
244 : // The jump fits within the range of an UImm8 operand, so cancel
245 : // the reservation and jump directly.
246 2712095 : constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
247 2712095 : bytecodes()->at(operand_location) = static_cast<uint8_t>(delta);
248 : } else {
249 : // The jump does not fit within the range of an UImm8 operand, so
250 : // commit reservation putting the offset into the constant pool,
251 : // and update the jump instruction and operand.
252 : size_t entry = constant_array_builder()->CommitReservedEntry(
253 82756 : OperandSize::kByte, Smi::FromInt(delta));
254 : DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)),
255 : OperandSize::kByte);
256 82756 : jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
257 82756 : bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
258 82756 : bytecodes()->at(operand_location) = static_cast<uint8_t>(entry);
259 : }
260 2794851 : }
261 :
262 83133 : void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location,
263 83133 : int delta) {
264 83133 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
265 : DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
266 : DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
267 : DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
268 : DCHECK_GT(delta, 0);
269 83133 : size_t operand_location = jump_location + 1;
270 : uint8_t operand_bytes[2];
271 166266 : if (Bytecodes::ScaleForUnsignedOperand(delta) <= OperandScale::kDouble) {
272 : // The jump fits within the range of an Imm16 operand, so cancel
273 : // the reservation and jump directly.
274 83126 : constant_array_builder()->DiscardReservedEntry(OperandSize::kShort);
275 83126 : WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(delta));
276 : } else {
277 : // The jump does not fit within the range of an Imm16 operand, so
278 : // commit reservation putting the offset into the constant pool,
279 : // and update the jump instruction and operand.
280 : size_t entry = constant_array_builder()->CommitReservedEntry(
281 7 : OperandSize::kShort, Smi::FromInt(delta));
282 7 : jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
283 7 : bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
284 7 : WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry));
285 : }
286 : DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
287 : bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder);
288 166266 : bytecodes()->at(operand_location++) = operand_bytes[0];
289 83133 : bytecodes()->at(operand_location) = operand_bytes[1];
290 83133 : }
291 :
292 7 : void BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location,
293 7 : int delta) {
294 : DCHECK(Bytecodes::IsJumpImmediate(
295 : Bytecodes::FromByte(bytecodes()->at(jump_location))));
296 7 : constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad);
297 : uint8_t operand_bytes[4];
298 7 : WriteUnalignedUInt32(operand_bytes, static_cast<uint32_t>(delta));
299 7 : size_t operand_location = jump_location + 1;
300 : DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
301 : bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder &&
302 : bytecodes()->at(operand_location + 2) == k8BitJumpPlaceholder &&
303 : bytecodes()->at(operand_location + 3) == k8BitJumpPlaceholder);
304 14 : bytecodes()->at(operand_location++) = operand_bytes[0];
305 14 : bytecodes()->at(operand_location++) = operand_bytes[1];
306 14 : bytecodes()->at(operand_location++) = operand_bytes[2];
307 7 : bytecodes()->at(operand_location) = operand_bytes[3];
308 7 : }
309 :
310 2877991 : void BytecodeArrayWriter::PatchJump(size_t jump_target, size_t jump_location) {
311 2877991 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
312 2877991 : int delta = static_cast<int>(jump_target - jump_location);
313 : int prefix_offset = 0;
314 : OperandScale operand_scale = OperandScale::kSingle;
315 2877991 : if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) {
316 : // If a prefix scaling bytecode is emitted the target offset is one
317 : // less than the case of no prefix scaling bytecode.
318 83140 : delta -= 1;
319 : prefix_offset = 1;
320 83140 : operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode);
321 : jump_bytecode =
322 83140 : Bytecodes::FromByte(bytecodes()->at(jump_location + prefix_offset));
323 : }
324 :
325 : DCHECK(Bytecodes::IsJump(jump_bytecode));
326 2877991 : switch (operand_scale) {
327 : case OperandScale::kSingle:
328 2794851 : PatchJumpWith8BitOperand(jump_location, delta);
329 2794851 : break;
330 : case OperandScale::kDouble:
331 83133 : PatchJumpWith16BitOperand(jump_location + prefix_offset, delta);
332 83133 : break;
333 : case OperandScale::kQuadruple:
334 7 : PatchJumpWith32BitOperand(jump_location + prefix_offset, delta);
335 7 : break;
336 : default:
337 0 : UNREACHABLE();
338 : }
339 2877991 : unbound_jumps_--;
340 2877991 : }
341 :
342 9208146 : void BytecodeArrayWriter::EmitJump(BytecodeNode* node, BytecodeLabel* label) {
343 : DCHECK(Bytecodes::IsJump(node->bytecode()));
344 : DCHECK_EQ(0u, node->operand(0));
345 :
346 3069382 : size_t current_offset = bytecodes()->size();
347 :
348 3069382 : if (label->is_bound()) {
349 191393 : CHECK_GE(current_offset, label->offset());
350 191393 : CHECK_LE(current_offset, static_cast<size_t>(kMaxUInt32));
351 : // Label has been bound already so this is a backwards jump.
352 191393 : uint32_t delta = static_cast<uint32_t>(current_offset - label->offset());
353 : OperandScale operand_scale = Bytecodes::ScaleForUnsignedOperand(delta);
354 191393 : if (operand_scale > OperandScale::kSingle) {
355 : // Adjust for scaling byte prefix for wide jump offset.
356 9241 : delta += 1;
357 : }
358 : DCHECK_EQ(Bytecode::kJumpLoop, node->bytecode());
359 191393 : node->update_operand0(delta);
360 : } else {
361 : // The label has not yet been bound so this is a forward reference
362 : // that will be patched when the label is bound. We create a
363 : // reservation in the constant pool so the jump can be patched
364 : // when the label is bound. The reservation means the maximum size
365 : // of the operand for the constant is known and the jump can
366 : // be emitted into the bytecode stream with space for the operand.
367 2877989 : unbound_jumps_++;
368 : label->set_referrer(current_offset);
369 : OperandSize reserved_operand_size =
370 2877989 : constant_array_builder()->CreateReservedEntry();
371 : DCHECK_NE(Bytecode::kJumpLoop, node->bytecode());
372 2877988 : switch (reserved_operand_size) {
373 : case OperandSize::kNone:
374 0 : UNREACHABLE();
375 : break;
376 : case OperandSize::kByte:
377 2794848 : node->update_operand0(k8BitJumpPlaceholder);
378 2794848 : break;
379 : case OperandSize::kShort:
380 83133 : node->update_operand0(k16BitJumpPlaceholder);
381 83133 : break;
382 : case OperandSize::kQuad:
383 7 : node->update_operand0(k32BitJumpPlaceholder);
384 7 : break;
385 : }
386 : }
387 3069381 : EmitBytecode(node);
388 3069380 : }
389 :
390 : } // namespace interpreter
391 : } // namespace internal
392 : } // namespace v8
|