v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
bytecode-array-iterator.cc
Go to the documentation of this file.
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
6
11
12namespace v8 {
13namespace internal {
14namespace interpreter {
15
17 Handle<BytecodeArray> bytecode_array, int initial_offset)
18 : bytecode_array_(bytecode_array),
19 start_(reinterpret_cast<uint8_t*>(
20 bytecode_array_->GetFirstBytecodeAddress())),
21 end_(start_ + bytecode_array_->length()),
23 operand_scale_(OperandScale::kSingle),
24 prefix_size_(0),
25 local_heap_(LocalHeap::Current()
26 ? LocalHeap::Current()
27 : Isolate::Current()->main_thread_local_heap()) {
30 if (initial_offset != 0) {
31 AdvanceTo(initial_offset);
32 }
33}
34
36 Handle<BytecodeArray> bytecode_array, int initial_offset,
38 : bytecode_array_(bytecode_array),
39 start_(reinterpret_cast<uint8_t*>(
40 bytecode_array_->GetFirstBytecodeAddress())),
41 end_(start_ + bytecode_array_->length()),
43 operand_scale_(OperandScale::kSingle),
44 prefix_size_(0),
45 local_heap_(nullptr) {
46 // Don't add a GC callback, since we're in a no_gc scope.
48 if (initial_offset != 0) {
49 AdvanceTo(initial_offset);
50 }
51}
52
58
61 while (current_offset() != offset && cursor_ < end_) {
62 Advance();
63 }
64 // Make sure we're always at a valid offset.
66}
67
69 DCHECK_GE(offset, 0);
70 if (offset < current_offset()) {
71 Reset();
72 }
73 // Advance to the given offset instead of just setting cursor_.
74 // This way, we can guarantee that the offset is always valid.
76}
77
82
83// protected
89
90// static
92 int offset) {
93 for (BytecodeArrayIterator it(bytecode_array); !it.done(); it.Advance()) {
94 if (it.current_offset() == offset) return true;
95 if (it.current_offset() > offset) break;
96 }
97 return false;
98}
99
100// static
102 Handle<BytecodeArray> bytecode_array, int offset) {
104 return it.CurrentBytecodeIsValidOSREntry();
105}
106
108 return current_bytecode() == interpreter::Bytecode::kJumpLoop;
109}
110
112 // Get the raw bytecode from the bytecode array. This may give us a
113 // scaling prefix, which we can patch with the matching debug-break
114 // variant.
115 uint8_t* cursor = cursor_ - prefix_size_;
117 if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return;
118 interpreter::Bytecode debugbreak =
120 *cursor = interpreter::Bytecodes::ToByte(debugbreak);
121}
122
124 int operand_index, OperandType operand_type) const {
125 DCHECK_GE(operand_index, 0);
127 DCHECK_EQ(operand_type,
130 Address operand_start =
131 reinterpret_cast<Address>(cursor_) +
134 return BytecodeDecoder::DecodeUnsignedOperand(operand_start, operand_type,
136}
137
139 int operand_index, OperandType operand_type) const {
140 DCHECK_GE(operand_index, 0);
142 DCHECK_EQ(operand_type,
145 Address operand_start =
146 reinterpret_cast<Address>(cursor_) +
149 return BytecodeDecoder::DecodeSignedOperand(operand_start, operand_type,
151}
152
153uint32_t BytecodeArrayIterator::GetFlag8Operand(int operand_index) const {
155 OperandType::kFlag8);
156 return GetUnsignedOperand(operand_index, OperandType::kFlag8);
157}
158
159uint32_t BytecodeArrayIterator::GetFlag16Operand(int operand_index) const {
161 OperandType::kFlag16);
162 return GetUnsignedOperand(operand_index, OperandType::kFlag16);
163}
164
166 int operand_index) const {
168 OperandType::kUImm);
169 return GetUnsignedOperand(operand_index, OperandType::kUImm);
170}
171
172int32_t BytecodeArrayIterator::GetImmediateOperand(int operand_index) const {
174 OperandType::kImm);
175 return GetSignedOperand(operand_index, OperandType::kImm);
176}
177
179 int operand_index) const {
181 OperandType::kRegCount);
182 return GetUnsignedOperand(operand_index, OperandType::kRegCount);
183}
184
185uint32_t BytecodeArrayIterator::GetIndexOperand(int operand_index) const {
186 OperandType operand_type =
188 DCHECK_EQ(operand_type, OperandType::kIdx);
189 return GetUnsignedOperand(operand_index, operand_type);
190}
191
193 int index = GetIndexOperand(operand_index);
194 return FeedbackVector::ToSlot(index);
195}
196
198 DCHECK_GE(parameter_index, 0);
199 // The parameter indices are shifted by 1 (receiver is the
200 // first entry).
201 return Register::FromParameterIndex(parameter_index + 1);
202}
203
205 OperandType operand_type =
207 Address operand_start =
208 reinterpret_cast<Address>(cursor_) +
211 return BytecodeDecoder::DecodeRegisterOperand(operand_start, operand_type,
213}
214
216 Bytecode bytecode = current_bytecode();
217 DCHECK(Bytecodes::IsAnyStar(bytecode));
218 if (Bytecodes::IsShortStar(bytecode)) {
219 return Register::FromShortStar(bytecode);
220 } else {
221 DCHECK_EQ(bytecode, Bytecode::kStar);
223 DCHECK_EQ(Bytecodes::GetOperandTypes(bytecode)[0], OperandType::kRegOut);
224 return GetRegisterOperand(0);
225 }
226}
227
229 int operand_index) const {
230 Register first = GetRegisterOperand(operand_index);
231 Register second(first.index() + 1);
232 return std::make_pair(first, second);
233}
234
236 int operand_index) const {
237 Register first = GetRegisterOperand(operand_index);
238 uint32_t count = GetRegisterCountOperand(operand_index + 1);
239 return RegisterList(first.index(), count);
240}
241
244 const OperandType* operand_types =
246 OperandType operand_type = operand_types[operand_index];
248 if (operand_type == OperandType::kRegList ||
249 operand_type == OperandType::kRegOutList) {
250 return GetRegisterCountOperand(operand_index + 1);
251 } else {
253 }
254}
255
257 int operand_index) const {
258 OperandType operand_type =
260 DCHECK_EQ(operand_type, OperandType::kRuntimeId);
261 uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type);
262 return static_cast<Runtime::FunctionId>(raw_id);
263}
264
266 int operand_index) const {
267 OperandType operand_type =
269 DCHECK_EQ(operand_type, OperandType::kNativeContextIndex);
270 return GetUnsignedOperand(operand_index, operand_type);
271}
272
274 int operand_index) const {
275 OperandType operand_type =
277 DCHECK_EQ(operand_type, OperandType::kIntrinsicId);
278 uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type);
280 static_cast<IntrinsicsHelper::IntrinsicId>(raw_id));
281}
282
283template <typename IsolateT>
285 int index, IsolateT* isolate) const {
286 return handle(bytecode_array()->constant_pool()->get(index), isolate);
287}
288
290 return IsSmi(bytecode_array()->constant_pool()->get(index));
291}
292
296
297template <typename IsolateT>
299 int operand_index, IsolateT* isolate) const {
300 return GetConstantAtIndex(GetIndexOperand(operand_index), isolate);
301}
302
305 int operand_index, Isolate* isolate) const;
307 int operand_index, LocalIsolate* isolate) const;
308
310 Bytecode bytecode = current_bytecode();
312 int relative_offset = GetUnsignedImmediateOperand(0);
313 if (bytecode == Bytecode::kJumpLoop) {
314 relative_offset = -relative_offset;
315 }
316 return relative_offset;
317 } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) {
319 return smi.value();
320 } else {
321 UNREACHABLE();
322 }
323}
324
328
330 const {
331 uint32_t table_start, table_size;
332 int32_t case_value_base;
333 if (current_bytecode() == Bytecode::kSwitchOnGeneratorState) {
334 table_start = GetIndexOperand(1);
335 table_size = GetUnsignedImmediateOperand(2);
336 case_value_base = 0;
337 } else {
338 DCHECK_EQ(current_bytecode(), Bytecode::kSwitchOnSmiNoFeedback);
339 table_start = GetIndexOperand(0);
340 table_size = GetUnsignedImmediateOperand(1);
341 case_value_base = GetImmediateOperand(2);
342 }
343 return JumpTableTargetOffsets(this, table_start, table_size, case_value_base);
344}
345
346int BytecodeArrayIterator::GetAbsoluteOffset(int relative_offset) const {
347 return current_offset() + relative_offset + prefix_size_;
348}
349
350std::ostream& BytecodeArrayIterator::PrintTo(std::ostream& os) const {
352}
353
356 uint8_t* start =
357 reinterpret_cast<uint8_t*>(bytecode_array_->GetFirstBytecodeAddress());
358 if (start != start_) {
359 start_ = start;
360 uint8_t* end = start + bytecode_array_->length();
361 size_t distance_to_end = end_ - cursor_;
362 cursor_ = end - distance_to_end;
363 end_ = end;
364 }
365}
366
368 const BytecodeArrayIterator* iterator, int table_start, int table_size,
369 int case_value_base)
370 : iterator_(iterator),
371 table_start_(table_start),
372 table_size_(table_size),
373 case_value_base_(case_value_base) {}
374
384 int ret = 0;
385 // TODO(leszeks): Is there a more efficient way of doing this than iterating?
386 for (JumpTableTargetOffset entry : *this) {
387 USE(entry);
388 ret++;
389 }
390 return ret;
391}
392
394 int case_value, int table_offset, int table_end,
396 : iterator_(iterator),
397 current_(Smi::zero()),
398 index_(case_value),
399 table_offset_(table_offset),
400 table_end_(table_end) {
402}
403
405 DCHECK_LT(table_offset_, table_end_);
406 return {index_, iterator_->GetAbsoluteOffset(Smi::ToInt(current_))};
407}
408
411 DCHECK_LT(table_offset_, table_end_);
412 ++table_offset_;
413 ++index_;
414 UpdateAndAdvanceToValid();
415 return *this;
416}
417
420 DCHECK_EQ(iterator_, other.iterator_);
421 DCHECK_EQ(table_end_, other.table_end_);
422 DCHECK_EQ(index_ - other.index_, table_offset_ - other.table_offset_);
423 return index_ != other.index_;
424}
425
427 while (table_offset_ < table_end_ &&
428 !iterator_->IsConstantAtIndexSmi(table_offset_)) {
429 ++table_offset_;
430 ++index_;
431 }
432
433 // Make sure we haven't reached the end of the table with a hole in current.
434 if (table_offset_ < table_end_) {
435 DCHECK(iterator_->IsConstantAtIndexSmi(table_offset_));
436 current_ = iterator_->GetConstantAtIndexAsSmi(table_offset_);
437 }
438}
439
440} // namespace interpreter
441} // namespace internal
442} // namespace v8
static FeedbackSlot ToSlot(intptr_t index)
void RemoveGCEpilogueCallback(GCEpilogueCallback *callback, void *data)
void AddGCEpilogueCallback(GCEpilogueCallback *callback, void *data, GCCallbacksInSafepoint::GCType gc_type=GCCallbacksInSafepoint::GCType::kAll)
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static bool IsValidOffset(Handle< BytecodeArray > bytecode_array, int offset)
FeedbackSlot GetSlotOperand(int operand_index) const
uint32_t GetUnsignedOperand(int operand_index, OperandType operand_type) const
uint32_t GetUnsignedImmediateOperand(int operand_index) const
DirectHandle< BytecodeArray > bytecode_array() const
BytecodeArrayIterator(Handle< BytecodeArray > bytecode_array, int initial_offset=0)
Handle< Object > GetConstantForIndexOperand(int operand_index, IsolateT *isolate) const
std::pair< Register, Register > GetRegisterPairOperand(int operand_index) const
Handle< Object > GetConstantAtIndex(int offset, IsolateT *isolate) const
RegisterList GetRegisterListOperand(int operand_index) const
uint32_t GetNativeContextIndexOperand(int operand_index) const
static bool IsValidOSREntryOffset(Handle< BytecodeArray > bytecode_array, int offset)
int32_t GetSignedOperand(int operand_index, OperandType operand_type) const
Runtime::FunctionId GetIntrinsicIdOperand(int operand_index) const
Runtime::FunctionId GetRuntimeIdOperand(int operand_index) const
static int32_t DecodeSignedOperand(Address operand_start, OperandType operand_type, OperandScale operand_scale)
static uint32_t DecodeUnsignedOperand(Address operand_start, OperandType operand_type, OperandScale operand_scale)
static Register DecodeRegisterOperand(Address operand_start, OperandType operand_type, OperandScale operand_scale)
static std::ostream & Decode(std::ostream &os, const uint8_t *bytecode_start, bool with_hex=true)
static const OperandType * GetOperandTypes(Bytecode bytecode)
Definition bytecodes.h:903
static Bytecode FromByte(uint8_t value)
Definition bytecodes.h:624
static constexpr bool IsAnyStar(Bytecode bytecode)
Definition bytecodes.h:737
static int GetNumberOfRegistersRepresentedBy(OperandType operand_type)
Definition bytecodes.h:1029
static constexpr bool IsJumpImmediate(Bytecode bytecode)
Definition bytecodes.h:777
static int GetOperandOffset(Bytecode bytecode, int i, OperandScale operand_scale)
Definition bytecodes.h:951
static Bytecode GetDebugBreak(Bytecode bytecode)
Definition bytecodes.cc:148
static bool IsDebugBreak(Bytecode bytecode)
Definition bytecodes.cc:167
static bool IsRegisterOperandType(OperandType operand_type)
Definition bytecodes.cc:180
static uint8_t ToByte(Bytecode bytecode)
Definition bytecodes.h:618
static OperandType GetOperandType(Bytecode bytecode, int i)
Definition bytecodes.h:894
static constexpr bool IsJumpConstant(Bytecode bytecode)
Definition bytecodes.h:784
static int NumberOfOperands(Bytecode bytecode)
Definition bytecodes.h:886
static bool IsUnsignedOperandType(OperandType operand_type)
Definition bytecodes.cc:321
static constexpr bool IsShortStar(Bytecode bytecode)
Definition bytecodes.h:732
static Runtime::FunctionId ToRuntimeId(IntrinsicId intrinsic_id)
iterator(int case_value, int table_offset, int table_end, const BytecodeArrayIterator *iterator)
JumpTableTargetOffsets(const BytecodeArrayIterator *iterator, int table_start, int table_size, int case_value_base)
static constexpr Register FromParameterIndex(int index)
static constexpr Register FromShortStar(Bytecode bytecode)
Register const index_
uint8_t *const start_
Definition assembler.cc:131
const v8::base::TimeTicks end_
Definition sweeper.cc:54
int start
int end
#define EXPORT_TEMPLATE_DEFINE(export)
int32_t offset
double second
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
base::uc32 current_
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
#define V8_EXPORT_PRIVATE
Definition macros.h:460