Bug Summary

File:out/../deps/v8/src/interpreter/bytecode-array-writer.cc
Warning:line 440, column 5
Value stored to 'jump_bytecode' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name bytecode-array-writer.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D V8_GYP_BUILD -D V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=64 -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D V8_TARGET_ARCH_X64 -D V8_HAVE_TARGET_OS -D V8_TARGET_OS_LINUX -D V8_EMBEDDER_STRING="-node.8" -D ENABLE_DISASSEMBLER -D V8_PROMISE_INTERNAL_FIELD_COUNT=1 -D V8_SHORT_BUILTIN_CALLS -D OBJECT_PRINT -D V8_INTL_SUPPORT -D V8_ATOMIC_OBJECT_FIELD_WRITES -D V8_ENABLE_LAZY_SOURCE_POSITIONS -D V8_USE_SIPHASH -D V8_SHARED_RO_HEAP -D V8_WIN64_UNWINDING_INFO -D V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -D V8_SNAPSHOT_COMPRESSION -D V8_ENABLE_WEBASSEMBLY -D V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS -D V8_ALLOCATION_FOLDING -D V8_ALLOCATION_SITE_TRACKING -D V8_SCRIPTORMODULE_LEGACY_LIFETIME -D V8_ADVANCED_BIGINT_ALGORITHMS -D ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_STATIC -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_STATIC_IMPLEMENTATION=1 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -I ../deps/v8 -I ../deps/v8/include -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/inspector-generated-output-root -I ../deps/v8/third_party/inspector_protocol -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/generate-bytecode-output-root -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -I ../deps/v8/third_party/zlib -I ../deps/v8/third_party/zlib/google -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-return-type -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../deps/v8/src/interpreter/bytecode-array-writer.cc
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/api-inl.h"
8#include "src/heap/local-factory-inl.h"
9#include "src/interpreter/bytecode-jump-table.h"
10#include "src/interpreter/bytecode-label.h"
11#include "src/interpreter/bytecode-node.h"
12#include "src/interpreter/bytecode-register.h"
13#include "src/interpreter/bytecode-source-info.h"
14#include "src/interpreter/constant-array-builder.h"
15#include "src/interpreter/handler-table-builder.h"
16#include "src/objects/objects-inl.h"
17
18namespace v8 {
19namespace internal {
20namespace interpreter {
21
22STATIC_CONST_MEMBER_DEFINITION const size_t
23 BytecodeArrayWriter::kMaxSizeOfPackedBytecode;
24
25BytecodeArrayWriter::BytecodeArrayWriter(
26 Zone* zone, ConstantArrayBuilder* constant_array_builder,
27 SourcePositionTableBuilder::RecordingMode source_position_mode)
28 : bytecodes_(zone),
29 unbound_jumps_(0),
30 source_position_table_builder_(zone, source_position_mode),
31 constant_array_builder_(constant_array_builder),
32 last_bytecode_(Bytecode::kIllegal),
33 last_bytecode_offset_(0),
34 last_bytecode_had_source_info_(false),
35 elide_noneffectful_bytecodes_(FLAG_ignition_elide_noneffectful_bytecodes),
36 exit_seen_in_block_(false) {
37 bytecodes_.reserve(512); // Derived via experimentation.
38}
39
40template <typename IsolateT>
41Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
42 IsolateT* isolate, int register_count, int parameter_count,
43 Handle<ByteArray> handler_table) {
44 DCHECK_EQ(0, unbound_jumps_)((void) 0);
45
46 int bytecode_size = static_cast<int>(bytecodes()->size());
47 int frame_size = register_count * kSystemPointerSize;
48 Handle<FixedArray> constant_pool =
49 constant_array_builder()->ToFixedArray(isolate);
50 Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray(
51 bytecode_size, &bytecodes()->front(), frame_size, parameter_count,
52 constant_pool);
53 bytecode_array->set_handler_table(*handler_table);
54 return bytecode_array;
55}
56
57template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
58 Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
59 Isolate* isolate, int register_count, int parameter_count,
60 Handle<ByteArray> handler_table);
61template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
62 Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
63 LocalIsolate* isolate, int register_count, int parameter_count,
64 Handle<ByteArray> handler_table);
65
66template <typename IsolateT>
67Handle<ByteArray> BytecodeArrayWriter::ToSourcePositionTable(
68 IsolateT* isolate) {
69 DCHECK(!source_position_table_builder_.Lazy())((void) 0);
70 Handle<ByteArray> source_position_table =
71 source_position_table_builder_.Omit()
72 ? isolate->factory()->empty_byte_array()
73 : source_position_table_builder_.ToSourcePositionTable(isolate);
74 return source_position_table;
75}
76
77template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
78 Handle<ByteArray> BytecodeArrayWriter::ToSourcePositionTable(
79 Isolate* isolate);
80template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
81 Handle<ByteArray> BytecodeArrayWriter::ToSourcePositionTable(
82 LocalIsolate* isolate);
83
84#ifdef DEBUG
85int BytecodeArrayWriter::CheckBytecodeMatches(BytecodeArray bytecode) {
86 int mismatches = false;
87 int bytecode_size = static_cast<int>(bytecodes()->size());
88 const byte* bytecode_ptr = &bytecodes()->front();
89 if (bytecode_size != bytecode.length()) mismatches = true;
90
91 // If there's a mismatch only in the length of the bytecode (very unlikely)
92 // then the first mismatch will be the first extra bytecode.
93 int first_mismatch = std::min(bytecode_size, bytecode.length());
94 for (int i = 0; i < first_mismatch; ++i) {
95 if (bytecode_ptr[i] != bytecode.get(i)) {
96 mismatches = true;
97 first_mismatch = i;
98 break;
99 }
100 }
101
102 if (mismatches) {
103 return first_mismatch;
104 }
105 return -1;
106}
107#endif
108
109void BytecodeArrayWriter::Write(BytecodeNode* node) {
110 DCHECK(!Bytecodes::IsJump(node->bytecode()))((void) 0);
111
112 if (exit_seen_in_block_) return; // Don't emit dead code.
113 UpdateExitSeenInBlock(node->bytecode());
114 MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
115
116 UpdateSourcePositionTable(node);
117 EmitBytecode(node);
118}
119
120void BytecodeArrayWriter::WriteJump(BytecodeNode* node, BytecodeLabel* label) {
121 DCHECK(Bytecodes::IsForwardJump(node->bytecode()))((void) 0);
122
123 if (exit_seen_in_block_) return; // Don't emit dead code.
124 UpdateExitSeenInBlock(node->bytecode());
125 MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
126
127 UpdateSourcePositionTable(node);
128 EmitJump(node, label);
129}
130
131void BytecodeArrayWriter::WriteJumpLoop(BytecodeNode* node,
132 BytecodeLoopHeader* loop_header) {
133 DCHECK_EQ(node->bytecode(), Bytecode::kJumpLoop)((void) 0);
134
135 if (exit_seen_in_block_) return; // Don't emit dead code.
136 UpdateExitSeenInBlock(node->bytecode());
137 MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
138
139 UpdateSourcePositionTable(node);
140 EmitJumpLoop(node, loop_header);
141}
142
143void BytecodeArrayWriter::WriteSwitch(BytecodeNode* node,
144 BytecodeJumpTable* jump_table) {
145 DCHECK(Bytecodes::IsSwitch(node->bytecode()))((void) 0);
146
147 if (exit_seen_in_block_) return; // Don't emit dead code.
148 UpdateExitSeenInBlock(node->bytecode());
149 MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
150
151 UpdateSourcePositionTable(node);
152 EmitSwitch(node, jump_table);
153}
154
155void BytecodeArrayWriter::BindLabel(BytecodeLabel* label) {
156 DCHECK(label->has_referrer_jump())((void) 0);
157 size_t current_offset = bytecodes()->size();
158 // Update the jump instruction's location.
159 PatchJump(current_offset, label->jump_offset());
160 label->bind();
161 StartBasicBlock();
162}
163
164void BytecodeArrayWriter::BindLoopHeader(BytecodeLoopHeader* loop_header) {
165 size_t current_offset = bytecodes()->size();
166 loop_header->bind_to(current_offset);
167 // Don't start a basic block when the entire loop is dead.
168 if (exit_seen_in_block_) return;
169 StartBasicBlock();
170}
171
172void BytecodeArrayWriter::BindJumpTableEntry(BytecodeJumpTable* jump_table,
173 int case_value) {
174 DCHECK(!jump_table->is_bound(case_value))((void) 0);
175
176 size_t current_offset = bytecodes()->size();
177 size_t relative_jump = current_offset - jump_table->switch_bytecode_offset();
178
179 constant_array_builder()->SetJumpTableSmi(
180 jump_table->ConstantPoolEntryFor(case_value),
181 Smi::FromInt(static_cast<int>(relative_jump)));
182 jump_table->mark_bound(case_value);
183
184 StartBasicBlock();
185}
186
187void BytecodeArrayWriter::BindHandlerTarget(
188 HandlerTableBuilder* handler_table_builder, int handler_id) {
189 size_t current_offset = bytecodes()->size();
190 StartBasicBlock();
191 handler_table_builder->SetHandlerTarget(handler_id, current_offset);
192}
193
194void BytecodeArrayWriter::BindTryRegionStart(
195 HandlerTableBuilder* handler_table_builder, int handler_id) {
196 size_t current_offset = bytecodes()->size();
197 // Try blocks don't have to be in a separate basic block, but we do have to
198 // invalidate the bytecode to avoid eliding it and changing the offset.
199 InvalidateLastBytecode();
200 handler_table_builder->SetTryRegionStart(handler_id, current_offset);
201}
202
203void BytecodeArrayWriter::BindTryRegionEnd(
204 HandlerTableBuilder* handler_table_builder, int handler_id) {
205 // Try blocks don't have to be in a separate basic block, but we do have to
206 // invalidate the bytecode to avoid eliding it and changing the offset.
207 InvalidateLastBytecode();
208 size_t current_offset = bytecodes()->size();
209 handler_table_builder->SetTryRegionEnd(handler_id, current_offset);
210}
211
212void BytecodeArrayWriter::SetFunctionEntrySourcePosition(int position) {
213 bool is_statement = false;
214 source_position_table_builder_.AddPosition(
215 kFunctionEntryBytecodeOffset, SourcePosition(position), is_statement);
216}
217
218void BytecodeArrayWriter::StartBasicBlock() {
219 InvalidateLastBytecode();
220 exit_seen_in_block_ = false;
221}
222
223void BytecodeArrayWriter::UpdateSourcePositionTable(
224 const BytecodeNode* const node) {
225 int bytecode_offset = static_cast<int>(bytecodes()->size());
226 const BytecodeSourceInfo& source_info = node->source_info();
227 if (source_info.is_valid()) {
228 source_position_table_builder()->AddPosition(
229 bytecode_offset, SourcePosition(source_info.source_position()),
230 source_info.is_statement());
231 }
232}
233
234void BytecodeArrayWriter::UpdateExitSeenInBlock(Bytecode bytecode) {
235 switch (bytecode) {
236 case Bytecode::kReturn:
237 case Bytecode::kThrow:
238 case Bytecode::kReThrow:
239 case Bytecode::kAbort:
240 case Bytecode::kJump:
241 case Bytecode::kJumpLoop:
242 case Bytecode::kJumpConstant:
243 case Bytecode::kSuspendGenerator:
244 exit_seen_in_block_ = true;
245 break;
246 default:
247 break;
248 }
249}
250
251void BytecodeArrayWriter::MaybeElideLastBytecode(Bytecode next_bytecode,
252 bool has_source_info) {
253 if (!elide_noneffectful_bytecodes_) return;
254
255 // If the last bytecode loaded the accumulator without any external effect,
256 // and the next bytecode clobbers this load without reading the accumulator,
257 // then the previous bytecode can be elided as it has no effect.
258 if (Bytecodes::IsAccumulatorLoadWithoutEffects(last_bytecode_) &&
259 Bytecodes::GetImplicitRegisterUse(next_bytecode) ==
260 ImplicitRegisterUse::kWriteAccumulator &&
261 (!last_bytecode_had_source_info_ || !has_source_info)) {
262 DCHECK_GT(bytecodes()->size(), last_bytecode_offset_)((void) 0);
263 bytecodes()->resize(last_bytecode_offset_);
264 // If the last bytecode had source info we will transfer the source info
265 // to this bytecode.
266 has_source_info |= last_bytecode_had_source_info_;
267 }
268 last_bytecode_ = next_bytecode;
269 last_bytecode_had_source_info_ = has_source_info;
270 last_bytecode_offset_ = bytecodes()->size();
271}
272
273void BytecodeArrayWriter::InvalidateLastBytecode() {
274 last_bytecode_ = Bytecode::kIllegal;
275}
276
277void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) {
278 DCHECK_NE(node->bytecode(), Bytecode::kIllegal)((void) 0);
279
280 Bytecode bytecode = node->bytecode();
281 OperandScale operand_scale = node->operand_scale();
282
283 if (operand_scale != OperandScale::kSingle) {
284 Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale);
285 bytecodes()->push_back(Bytecodes::ToByte(prefix));
286 }
287 bytecodes()->push_back(Bytecodes::ToByte(bytecode));
288
289 const uint32_t* const operands = node->operands();
290 const int operand_count = node->operand_count();
291 const OperandSize* operand_sizes =
292 Bytecodes::GetOperandSizes(bytecode, operand_scale);
293 for (int i = 0; i < operand_count; ++i) {
294 switch (operand_sizes[i]) {
295 case OperandSize::kNone:
296 UNREACHABLE()V8_Fatal("unreachable code");
297 case OperandSize::kByte:
298 bytecodes()->push_back(static_cast<uint8_t>(operands[i]));
299 break;
300 case OperandSize::kShort: {
301 uint16_t operand = static_cast<uint16_t>(operands[i]);
302 const uint8_t* raw_operand = reinterpret_cast<const uint8_t*>(&operand);
303 bytecodes()->push_back(raw_operand[0]);
304 bytecodes()->push_back(raw_operand[1]);
305 break;
306 }
307 case OperandSize::kQuad: {
308 const uint8_t* raw_operand =
309 reinterpret_cast<const uint8_t*>(&operands[i]);
310 bytecodes()->push_back(raw_operand[0]);
311 bytecodes()->push_back(raw_operand[1]);
312 bytecodes()->push_back(raw_operand[2]);
313 bytecodes()->push_back(raw_operand[3]);
314 break;
315 }
316 }
317 }
318}
319
320// static
321Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
322 switch (jump_bytecode) {
323 case Bytecode::kJump:
324 return Bytecode::kJumpConstant;
325 case Bytecode::kJumpIfTrue:
326 return Bytecode::kJumpIfTrueConstant;
327 case Bytecode::kJumpIfFalse:
328 return Bytecode::kJumpIfFalseConstant;
329 case Bytecode::kJumpIfToBooleanTrue:
330 return Bytecode::kJumpIfToBooleanTrueConstant;
331 case Bytecode::kJumpIfToBooleanFalse:
332 return Bytecode::kJumpIfToBooleanFalseConstant;
333 case Bytecode::kJumpIfNull:
334 return Bytecode::kJumpIfNullConstant;
335 case Bytecode::kJumpIfNotNull:
336 return Bytecode::kJumpIfNotNullConstant;
337 case Bytecode::kJumpIfUndefined:
338 return Bytecode::kJumpIfUndefinedConstant;
339 case Bytecode::kJumpIfNotUndefined:
340 return Bytecode::kJumpIfNotUndefinedConstant;
341 case Bytecode::kJumpIfUndefinedOrNull:
342 return Bytecode::kJumpIfUndefinedOrNullConstant;
343 case Bytecode::kJumpIfJSReceiver:
344 return Bytecode::kJumpIfJSReceiverConstant;
345 default:
346 UNREACHABLE()V8_Fatal("unreachable code");
347 }
348}
349
350void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location,
351 int delta) {
352 Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
353 DCHECK(Bytecodes::IsForwardJump(jump_bytecode))((void) 0);
354 DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode))((void) 0);
355 DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm)((void) 0);
356 DCHECK_GT(delta, 0)((void) 0);
357 size_t operand_location = jump_location + 1;
358 DCHECK_EQ(bytecodes()->at(operand_location), k8BitJumpPlaceholder)((void) 0);
359 if (Bytecodes::ScaleForUnsignedOperand(delta) == OperandScale::kSingle) {
360 // The jump fits within the range of an UImm8 operand, so cancel
361 // the reservation and jump directly.
362 constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
363 bytecodes()->at(operand_location) = static_cast<uint8_t>(delta);
364 } else {
365 // The jump does not fit within the range of an UImm8 operand, so
366 // commit reservation putting the offset into the constant pool,
367 // and update the jump instruction and operand.
368 size_t entry = constant_array_builder()->CommitReservedEntry(
369 OperandSize::kByte, Smi::FromInt(delta));
370 DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)),((void) 0)
371 OperandSize::kByte)((void) 0);
372 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
373 bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
374 bytecodes()->at(operand_location) = static_cast<uint8_t>(entry);
375 }
376}
377
378void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location,
379 int delta) {
380 Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
381 DCHECK(Bytecodes::IsForwardJump(jump_bytecode))((void) 0);
382 DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode))((void) 0);
383 DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm)((void) 0);
384 DCHECK_GT(delta, 0)((void) 0);
385 size_t operand_location = jump_location + 1;
386 uint8_t operand_bytes[2];
387 if (Bytecodes::ScaleForUnsignedOperand(delta) <= OperandScale::kDouble) {
388 // The jump fits within the range of an Imm16 operand, so cancel
389 // the reservation and jump directly.
390 constant_array_builder()->DiscardReservedEntry(OperandSize::kShort);
391 base::WriteUnalignedValue<uint16_t>(
392 reinterpret_cast<Address>(operand_bytes), static_cast<uint16_t>(delta));
393 } else {
394 // The jump does not fit within the range of an Imm16 operand, so
395 // commit reservation putting the offset into the constant pool,
396 // and update the jump instruction and operand.
397 size_t entry = constant_array_builder()->CommitReservedEntry(
398 OperandSize::kShort, Smi::FromInt(delta));
399 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
400 bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
401 base::WriteUnalignedValue<uint16_t>(
402 reinterpret_cast<Address>(operand_bytes), static_cast<uint16_t>(entry));
403 }
404 DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&((void) 0)
405 bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder)((void) 0);
406 bytecodes()->at(operand_location++) = operand_bytes[0];
407 bytecodes()->at(operand_location) = operand_bytes[1];
408}
409
410void BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location,
411 int delta) {
412 DCHECK(Bytecodes::IsJumpImmediate(((void) 0)
413 Bytecodes::FromByte(bytecodes()->at(jump_location))))((void) 0);
414 constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad);
415 uint8_t operand_bytes[4];
416 base::WriteUnalignedValue<uint32_t>(reinterpret_cast<Address>(operand_bytes),
417 static_cast<uint32_t>(delta));
418 size_t operand_location = jump_location + 1;
419 DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&((void) 0)
420 bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder &&((void) 0)
421 bytecodes()->at(operand_location + 2) == k8BitJumpPlaceholder &&((void) 0)
422 bytecodes()->at(operand_location + 3) == k8BitJumpPlaceholder)((void) 0);
423 bytecodes()->at(operand_location++) = operand_bytes[0];
424 bytecodes()->at(operand_location++) = operand_bytes[1];
425 bytecodes()->at(operand_location++) = operand_bytes[2];
426 bytecodes()->at(operand_location) = operand_bytes[3];
427}
428
429void BytecodeArrayWriter::PatchJump(size_t jump_target, size_t jump_location) {
430 Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
431 int delta = static_cast<int>(jump_target - jump_location);
432 int prefix_offset = 0;
433 OperandScale operand_scale = OperandScale::kSingle;
434 if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) {
435 // If a prefix scaling bytecode is emitted the target offset is one
436 // less than the case of no prefix scaling bytecode.
437 delta -= 1;
438 prefix_offset = 1;
439 operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode);
440 jump_bytecode =
Value stored to 'jump_bytecode' is never read
441 Bytecodes::FromByte(bytecodes()->at(jump_location + prefix_offset));
442 }
443
444 DCHECK(Bytecodes::IsJump(jump_bytecode))((void) 0);
445 switch (operand_scale) {
446 case OperandScale::kSingle:
447 PatchJumpWith8BitOperand(jump_location, delta);
448 break;
449 case OperandScale::kDouble:
450 PatchJumpWith16BitOperand(jump_location + prefix_offset, delta);
451 break;
452 case OperandScale::kQuadruple:
453 PatchJumpWith32BitOperand(jump_location + prefix_offset, delta);
454 break;
455 default:
456 UNREACHABLE()V8_Fatal("unreachable code");
457 }
458 unbound_jumps_--;
459}
460
461void BytecodeArrayWriter::EmitJumpLoop(BytecodeNode* node,
462 BytecodeLoopHeader* loop_header) {
463 DCHECK_EQ(node->bytecode(), Bytecode::kJumpLoop)((void) 0);
464 DCHECK_EQ(0u, node->operand(0))((void) 0);
465
466 size_t current_offset = bytecodes()->size();
467
468 CHECK_GE(current_offset, loop_header->offset())do { bool _cmp = ::v8::base::CmpGEImpl< typename ::v8::base
::pass_value_or_ref<decltype(current_offset)>::type, typename
::v8::base::pass_value_or_ref<decltype(loop_header->offset
())>::type>((current_offset), (loop_header->offset()
)); do { if ((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal("Check failed: %s."
, "current_offset" " " ">=" " " "loop_header->offset()"
); } } while (false); } while (false)
;
469 CHECK_LE(current_offset, static_cast<size_t>(kMaxUInt32))do { bool _cmp = ::v8::base::CmpLEImpl< typename ::v8::base
::pass_value_or_ref<decltype(current_offset)>::type, typename
::v8::base::pass_value_or_ref<decltype(static_cast<size_t
>(kMaxUInt32))>::type>((current_offset), (static_cast
<size_t>(kMaxUInt32))); do { if ((__builtin_expect(!!(!
(_cmp)), 0))) { V8_Fatal("Check failed: %s.", "current_offset"
" " "<=" " " "static_cast<size_t>(kMaxUInt32)"); } }
while (false); } while (false)
;
470 // Label has been bound already so this is a backwards jump.
471 uint32_t delta =
472 static_cast<uint32_t>(current_offset - loop_header->offset());
473 OperandScale operand_scale = Bytecodes::ScaleForUnsignedOperand(delta);
474 if (operand_scale > OperandScale::kSingle) {
475 // Adjust for scaling byte prefix for wide jump offset.
476 delta += 1;
477 }
478 node->update_operand0(delta);
479 EmitBytecode(node);
480}
481
482void BytecodeArrayWriter::EmitJump(BytecodeNode* node, BytecodeLabel* label) {
483 DCHECK(Bytecodes::IsForwardJump(node->bytecode()))((void) 0);
484 DCHECK_EQ(0u, node->operand(0))((void) 0);
485
486 size_t current_offset = bytecodes()->size();
487
488 // The label has not yet been bound so this is a forward reference
489 // that will be patched when the label is bound. We create a
490 // reservation in the constant pool so the jump can be patched
491 // when the label is bound. The reservation means the maximum size
492 // of the operand for the constant is known and the jump can
493 // be emitted into the bytecode stream with space for the operand.
494 unbound_jumps_++;
495 label->set_referrer(current_offset);
496 OperandSize reserved_operand_size =
497 constant_array_builder()->CreateReservedEntry();
498 DCHECK_NE(Bytecode::kJumpLoop, node->bytecode())((void) 0);
499 switch (reserved_operand_size) {
500 case OperandSize::kNone:
501 UNREACHABLE()V8_Fatal("unreachable code");
502 case OperandSize::kByte:
503 node->update_operand0(k8BitJumpPlaceholder);
504 break;
505 case OperandSize::kShort:
506 node->update_operand0(k16BitJumpPlaceholder);
507 break;
508 case OperandSize::kQuad:
509 node->update_operand0(k32BitJumpPlaceholder);
510 break;
511 }
512 EmitBytecode(node);
513}
514
515void BytecodeArrayWriter::EmitSwitch(BytecodeNode* node,
516 BytecodeJumpTable* jump_table) {
517 DCHECK(Bytecodes::IsSwitch(node->bytecode()))((void) 0);
518
519 size_t current_offset = bytecodes()->size();
520 if (node->operand_scale() > OperandScale::kSingle) {
521 // Adjust for scaling byte prefix.
522 current_offset += 1;
523 }
524 jump_table->set_switch_bytecode_offset(current_offset);
525
526 EmitBytecode(node);
527}
528
529} // namespace interpreter
530} // namespace internal
531} // namespace v8