blob: 5ddda6790e06a5d55e0f26e9cb86fb8851ecae0d [file] [log] [blame]
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTERPRETER_BYTECODE_ARRAY_ITERATOR_H_
#define V8_INTERPRETER_BYTECODE_ARRAY_ITERATOR_H_
#include <memory>
#include "include/v8-callbacks.h"
#include "src/common/globals.h"
#include "src/handles/handles.h"
#include "src/interpreter/bytecode-register.h"
#include "src/interpreter/bytecodes.h"
#include "src/objects/objects.h"
#include "src/objects/smi.h"
#include "src/runtime/runtime.h"
namespace v8 {
namespace internal {
class BytecodeArray;
namespace interpreter {
class BytecodeArrayIterator;
struct V8_EXPORT_PRIVATE JumpTableTargetOffset {
int case_value;
int target_offset;
};
class V8_EXPORT_PRIVATE JumpTableTargetOffsets final {
public:
// Minimal iterator implementation for use in ranged-for.
class V8_EXPORT_PRIVATE iterator final {
public:
iterator(int case_value, int table_offset, int table_end,
const BytecodeArrayIterator* iterator);
JumpTableTargetOffset operator*();
iterator& operator++();
bool operator!=(const iterator& other);
private:
void UpdateAndAdvanceToValid();
const BytecodeArrayIterator* iterator_;
Tagged<Smi> current_;
int index_;
int table_offset_;
int table_end_;
};
JumpTableTargetOffsets(const BytecodeArrayIterator* iterator, int table_start,
int table_size, int case_value_base);
iterator begin() const;
iterator end() const;
int size() const;
private:
const BytecodeArrayIterator* iterator_;
int table_start_;
int table_size_;
int case_value_base_;
};
class V8_EXPORT_PRIVATE BytecodeArrayIterator {
public:
explicit BytecodeArrayIterator(Handle<BytecodeArray> bytecode_array,
int initial_offset = 0);
BytecodeArrayIterator(Handle<BytecodeArray> bytecode_array,
int initial_offset, DisallowGarbageCollection& no_gc);
~BytecodeArrayIterator();
BytecodeArrayIterator(const BytecodeArrayIterator&) = delete;
BytecodeArrayIterator& operator=(const BytecodeArrayIterator&) = delete;
inline void Advance() {
cursor_ += current_bytecode_size_without_prefix();
UpdateOperandScale();
}
void SetOffset(int offset);
void Reset() { SetOffset(0); }
// Whether the given offset is reachable in this bytecode array.
static bool IsValidOffset(Handle<BytecodeArray> bytecode_array, int offset);
void ApplyDebugBreak();
inline Bytecode current_bytecode() const {
DCHECK(!done());
uint8_t current_byte = *cursor_;
Bytecode current_bytecode = Bytecodes::FromByte(current_byte);
DCHECK(!Bytecodes::IsPrefixScalingBytecode(current_bytecode));
return current_bytecode;
}
int current_bytecode_size() const {
return prefix_size_ + current_bytecode_size_without_prefix();
}
int current_bytecode_size_without_prefix() const {
return Bytecodes::Size(current_bytecode(), current_operand_scale());
}
int current_offset() const {
return static_cast<int>(cursor_ - start_ - prefix_size_);
}
uint8_t* current_address() const { return cursor_ - prefix_size_; }
int next_offset() const { return current_offset() + current_bytecode_size(); }
Bytecode next_bytecode() const {
uint8_t* next_cursor = cursor_ + current_bytecode_size_without_prefix();
if (next_cursor == end_) return Bytecode::kIllegal;
Bytecode next_bytecode = Bytecodes::FromByte(*next_cursor);
if (Bytecodes::IsPrefixScalingBytecode(next_bytecode)) {
next_bytecode = Bytecodes::FromByte(*(next_cursor + 1));
}
return next_bytecode;
}
OperandScale current_operand_scale() const { return operand_scale_; }
Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
uint32_t GetFlag8Operand(int operand_index) const;
uint32_t GetFlag16Operand(int operand_index) const;
uint32_t GetUnsignedImmediateOperand(int operand_index) const;
int32_t GetImmediateOperand(int operand_index) const;
uint32_t GetIndexOperand(int operand_index) const;
FeedbackSlot GetSlotOperand(int operand_index) const;
Register GetReceiver() const;
Register GetParameter(int parameter_index) const;
uint32_t GetRegisterCountOperand(int operand_index) const;
Register GetRegisterOperand(int operand_index) const;
Register GetStarTargetRegister() const;
std::pair<Register, Register> GetRegisterPairOperand(int operand_index) const;
RegisterList GetRegisterListOperand(int operand_index) const;
int GetRegisterOperandRange(int operand_index) const;
Runtime::FunctionId GetRuntimeIdOperand(int operand_index) const;
Runtime::FunctionId GetIntrinsicIdOperand(int operand_index) const;
uint32_t GetNativeContextIndexOperand(int operand_index) const;
template <typename IsolateT>
Handle<Object> GetConstantAtIndex(int offset, IsolateT* isolate) const;
bool IsConstantAtIndexSmi(int offset) const;
Tagged<Smi> GetConstantAtIndexAsSmi(int offset) const;
template <typename IsolateT>
Handle<Object> GetConstantForIndexOperand(int operand_index,
IsolateT* isolate) const;
// Returns the relative offset of the branch target at the current bytecode.
// It is an error to call this method if the bytecode is not for a jump or
// conditional jump. Returns a negative offset for backward jumps.
int GetRelativeJumpTargetOffset() const;
// Returns the absolute offset of the branch target at the current bytecode.
// It is an error to call this method if the bytecode is not for a jump or
// conditional jump.
int GetJumpTargetOffset() const;
// Returns an iterator over the absolute offsets of the targets of the current
// switch bytecode's jump table. It is an error to call this method if the
// bytecode is not a switch.
JumpTableTargetOffsets GetJumpTableTargetOffsets() const;
// Returns the absolute offset of the bytecode at the given relative offset
// from the current bytecode.
int GetAbsoluteOffset(int relative_offset) const;
std::ostream& PrintTo(std::ostream& os) const;
static void UpdatePointersCallback(void* iterator) {
reinterpret_cast<BytecodeArrayIterator*>(iterator)->UpdatePointers();
}
void UpdatePointers();
inline bool done() const { return cursor_ >= end_; }
bool operator==(const BytecodeArrayIterator& other) const {
return cursor_ == other.cursor_;
}
bool operator!=(const BytecodeArrayIterator& other) const {
return cursor_ != other.cursor_;
}
private:
uint32_t GetUnsignedOperand(int operand_index,
OperandType operand_type) const;
int32_t GetSignedOperand(int operand_index, OperandType operand_type) const;
inline void UpdateOperandScale() {
if (done()) return;
uint8_t current_byte = *cursor_;
Bytecode current_bytecode = Bytecodes::FromByte(current_byte);
if (Bytecodes::IsPrefixScalingBytecode(current_bytecode)) {
operand_scale_ =
Bytecodes::PrefixBytecodeToOperandScale(current_bytecode);
++cursor_;
prefix_size_ = 1;
} else {
operand_scale_ = OperandScale::kSingle;
prefix_size_ = 0;
}
}
Handle<BytecodeArray> bytecode_array_;
uint8_t* start_;
uint8_t* end_;
// The cursor always points to the active bytecode. If there's a prefix, the
// prefix is at (cursor - 1).
uint8_t* cursor_;
OperandScale operand_scale_;
int prefix_size_;
LocalHeap* const local_heap_;
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_ARRAY_ITERATOR_H_