1 // Copyright 2016 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 #ifndef V8_INTERPRETER_BYTECODE_ARRAY_ITERATOR_H_ 6 #define V8_INTERPRETER_BYTECODE_ARRAY_ITERATOR_H_ 7 8 #include <memory> 9 10 #include "src/base/optional.h" 11 #include "src/common/globals.h" 12 #include "src/handles/handles.h" 13 #include "src/interpreter/bytecode-register.h" 14 #include "src/interpreter/bytecodes.h" 15 #include "src/objects/objects.h" 16 #include "src/objects/smi.h" 17 #include "src/runtime/runtime.h" 18 19 namespace v8 { 20 namespace internal { 21 22 class BytecodeArray; 23 24 namespace interpreter { 25 26 class BytecodeArrayIterator; 27 28 struct V8_EXPORT_PRIVATE JumpTableTargetOffset { 29 int case_value; 30 int target_offset; 31 }; 32 33 class V8_EXPORT_PRIVATE JumpTableTargetOffsets final { 34 public: 35 // Minimal iterator implementation for use in ranged-for. 36 class V8_EXPORT_PRIVATE iterator final { 37 public: 38 iterator(int case_value, int table_offset, int table_end, 39 const BytecodeArrayIterator* iterator); 40 41 JumpTableTargetOffset operator*(); 42 iterator& operator++(); 43 bool operator!=(const iterator& other); 44 45 private: 46 void UpdateAndAdvanceToValid(); 47 48 const BytecodeArrayIterator* iterator_; 49 Smi current_; 50 int index_; 51 int table_offset_; 52 int table_end_; 53 }; 54 55 JumpTableTargetOffsets(const BytecodeArrayIterator* iterator, int table_start, 56 int table_size, int case_value_base); 57 58 iterator begin() const; 59 iterator end() const; 60 61 int size() const; 62 63 private: 64 const BytecodeArrayIterator* iterator_; 65 int table_start_; 66 int table_size_; 67 int case_value_base_; 68 }; 69 70 class V8_EXPORT_PRIVATE BytecodeArrayIterator { 71 public: 72 BytecodeArrayIterator(Handle<BytecodeArray> bytecode_array, 73 int initial_offset = 0); 74 ~BytecodeArrayIterator(); 75 76 BytecodeArrayIterator(const BytecodeArrayIterator&) = delete; 77 BytecodeArrayIterator& operator=(const BytecodeArrayIterator&) = delete; 78 Advance()79 inline void Advance() { 80 cursor_ += current_bytecode_size_without_prefix(); 81 UpdateOperandScale(); 82 } 83 void SetOffset(int offset); Reset()84 void Reset() { SetOffset(0); } 85 86 void ApplyDebugBreak(); 87 current_bytecode()88 inline Bytecode current_bytecode() const { 89 DCHECK(!done()); 90 uint8_t current_byte = *cursor_; 91 Bytecode current_bytecode = Bytecodes::FromByte(current_byte); 92 DCHECK(!Bytecodes::IsPrefixScalingBytecode(current_bytecode)); 93 return current_bytecode; 94 } current_bytecode_size()95 int current_bytecode_size() const { 96 return prefix_size_ + current_bytecode_size_without_prefix(); 97 } current_bytecode_size_without_prefix()98 int current_bytecode_size_without_prefix() const { 99 return Bytecodes::Size(current_bytecode(), current_operand_scale()); 100 } current_offset()101 int current_offset() const { 102 return static_cast<int>(cursor_ - start_ - prefix_size_); 103 } next_offset()104 int next_offset() const { return current_offset() + current_bytecode_size(); } current_operand_scale()105 OperandScale current_operand_scale() const { return operand_scale_; } bytecode_array()106 Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; } 107 108 uint32_t GetFlagOperand(int operand_index) const; 109 uint32_t GetUnsignedImmediateOperand(int operand_index) const; 110 int32_t GetImmediateOperand(int operand_index) const; 111 uint32_t GetIndexOperand(int operand_index) const; 112 FeedbackSlot GetSlotOperand(int operand_index) const; 113 Register GetReceiver() const; 114 Register GetParameter(int parameter_index) const; 115 uint32_t GetRegisterCountOperand(int operand_index) const; 116 Register GetRegisterOperand(int operand_index) const; 117 std::pair<Register, Register> GetRegisterPairOperand(int operand_index) const; 118 RegisterList GetRegisterListOperand(int operand_index) const; 119 int GetRegisterOperandRange(int operand_index) const; 120 Runtime::FunctionId GetRuntimeIdOperand(int operand_index) const; 121 Runtime::FunctionId GetIntrinsicIdOperand(int operand_index) const; 122 uint32_t GetNativeContextIndexOperand(int operand_index) const; 123 template <typename IsolateT> 124 Handle<Object> GetConstantAtIndex(int offset, IsolateT* isolate) const; 125 bool IsConstantAtIndexSmi(int offset) const; 126 Smi GetConstantAtIndexAsSmi(int offset) const; 127 template <typename IsolateT> 128 Handle<Object> GetConstantForIndexOperand(int operand_index, 129 IsolateT* isolate) const; 130 131 // Returns the relative offset of the branch target at the current bytecode. 132 // It is an error to call this method if the bytecode is not for a jump or 133 // conditional jump. Returns a negative offset for backward jumps. 134 int GetRelativeJumpTargetOffset() const; 135 // Returns the absolute offset of the branch target at the current bytecode. 136 // It is an error to call this method if the bytecode is not for a jump or 137 // conditional jump. 138 int GetJumpTargetOffset() const; 139 // Returns an iterator over the absolute offsets of the targets of the current 140 // switch bytecode's jump table. It is an error to call this method if the 141 // bytecode is not a switch. 142 JumpTableTargetOffsets GetJumpTableTargetOffsets() const; 143 144 // Returns the absolute offset of the bytecode at the given relative offset 145 // from the current bytecode. 146 int GetAbsoluteOffset(int relative_offset) const; 147 148 std::ostream& PrintTo(std::ostream& os) const; 149 UpdatePointersCallback(void * iterator)150 static void UpdatePointersCallback(void* iterator) { 151 reinterpret_cast<BytecodeArrayIterator*>(iterator)->UpdatePointers(); 152 } 153 154 void UpdatePointers(); 155 done()156 inline bool done() const { return cursor_ >= end_; } 157 158 private: 159 uint32_t GetUnsignedOperand(int operand_index, 160 OperandType operand_type) const; 161 int32_t GetSignedOperand(int operand_index, OperandType operand_type) const; 162 UpdateOperandScale()163 inline void UpdateOperandScale() { 164 if (done()) return; 165 uint8_t current_byte = *cursor_; 166 Bytecode current_bytecode = Bytecodes::FromByte(current_byte); 167 if (Bytecodes::IsPrefixScalingBytecode(current_bytecode)) { 168 operand_scale_ = 169 Bytecodes::PrefixBytecodeToOperandScale(current_bytecode); 170 ++cursor_; 171 prefix_size_ = 1; 172 } else { 173 operand_scale_ = OperandScale::kSingle; 174 prefix_size_ = 0; 175 } 176 } 177 178 Handle<BytecodeArray> bytecode_array_; 179 uint8_t* start_; 180 uint8_t* end_; 181 // The cursor always points to the active bytecode. If there's a prefix, the 182 // prefix is at (cursor - 1). 183 uint8_t* cursor_; 184 OperandScale operand_scale_; 185 int prefix_size_; 186 LocalHeap* const local_heap_; 187 }; 188 189 } // namespace interpreter 190 } // namespace internal 191 } // namespace v8 192 193 #endif // V8_INTERPRETER_BYTECODE_ARRAY_ITERATOR_H_ 194