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-accessor.h" 6 7 #include "src/feedback-vector.h" 8 #include "src/interpreter/bytecode-decoder.h" 9 #include "src/interpreter/interpreter-intrinsics.h" 10 #include "src/objects-inl.h" 11 #include "src/objects/code-inl.h" 12 13 namespace v8 { 14 namespace internal { 15 namespace interpreter { 16 17 BytecodeArrayAccessor::BytecodeArrayAccessor( 18 Handle<BytecodeArray> bytecode_array, int initial_offset) 19 : bytecode_array_(bytecode_array), 20 bytecode_offset_(initial_offset), 21 operand_scale_(OperandScale::kSingle), 22 prefix_offset_(0) { 23 UpdateOperandScale(); 24 } 25 26 void BytecodeArrayAccessor::SetOffset(int offset) { 27 bytecode_offset_ = offset; 28 UpdateOperandScale(); 29 } 30 31 void BytecodeArrayAccessor::ApplyDebugBreak() { 32 // Get the raw bytecode from the bytecode array. This may give us a 33 // scaling prefix, which we can patch with the matching debug-break 34 // variant. 35 interpreter::Bytecode bytecode = 36 interpreter::Bytecodes::FromByte(bytecode_array_->get(bytecode_offset_)); 37 if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return; 38 interpreter::Bytecode debugbreak = 39 interpreter::Bytecodes::GetDebugBreak(bytecode); 40 bytecode_array_->set(bytecode_offset_, 41 interpreter::Bytecodes::ToByte(debugbreak)); 42 } 43 44 void BytecodeArrayAccessor::UpdateOperandScale() { 45 if (OffsetInBounds()) { 46 uint8_t current_byte = bytecode_array()->get(bytecode_offset_); 47 Bytecode current_bytecode = Bytecodes::FromByte(current_byte); 48 if (Bytecodes::IsPrefixScalingBytecode(current_bytecode)) { 49 operand_scale_ = 50 Bytecodes::PrefixBytecodeToOperandScale(current_bytecode); 51 prefix_offset_ = 1; 52 } else { 53 operand_scale_ = OperandScale::kSingle; 54 prefix_offset_ = 0; 55 } 56 } 57 } 58 59 bool BytecodeArrayAccessor::OffsetInBounds() const { 60 return bytecode_offset_ >= 0 && bytecode_offset_ < bytecode_array()->length(); 61 } 62 63 Bytecode BytecodeArrayAccessor::current_bytecode() const { 64 DCHECK(OffsetInBounds()); 65 uint8_t current_byte = 66 bytecode_array()->get(bytecode_offset_ + current_prefix_offset()); 67 Bytecode current_bytecode = Bytecodes::FromByte(current_byte); 68 DCHECK(!Bytecodes::IsPrefixScalingBytecode(current_bytecode)); 69 return current_bytecode; 70 } 71 72 int BytecodeArrayAccessor::current_bytecode_size() const { 73 return current_prefix_offset() + 74 Bytecodes::Size(current_bytecode(), current_operand_scale()); 75 } 76 77 uint32_t BytecodeArrayAccessor::GetUnsignedOperand( 78 int operand_index, OperandType operand_type) const { 79 DCHECK_GE(operand_index, 0); 80 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); 81 DCHECK_EQ(operand_type, 82 Bytecodes::GetOperandType(current_bytecode(), operand_index)); 83 DCHECK(Bytecodes::IsUnsignedOperandType(operand_type)); 84 Address operand_start = 85 bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ + 86 current_prefix_offset() + 87 Bytecodes::GetOperandOffset(current_bytecode(), operand_index, 88 current_operand_scale()); 89 return BytecodeDecoder::DecodeUnsignedOperand(operand_start, operand_type, 90 current_operand_scale()); 91 } 92 93 int32_t BytecodeArrayAccessor::GetSignedOperand( 94 int operand_index, OperandType operand_type) const { 95 DCHECK_GE(operand_index, 0); 96 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); 97 DCHECK_EQ(operand_type, 98 Bytecodes::GetOperandType(current_bytecode(), operand_index)); 99 DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type)); 100 Address operand_start = 101 bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ + 102 current_prefix_offset() + 103 Bytecodes::GetOperandOffset(current_bytecode(), operand_index, 104 current_operand_scale()); 105 return BytecodeDecoder::DecodeSignedOperand(operand_start, operand_type, 106 current_operand_scale()); 107 } 108 109 uint32_t BytecodeArrayAccessor::GetFlagOperand(int operand_index) const { 110 DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), 111 OperandType::kFlag8); 112 return GetUnsignedOperand(operand_index, OperandType::kFlag8); 113 } 114 115 uint32_t BytecodeArrayAccessor::GetUnsignedImmediateOperand( 116 int operand_index) const { 117 DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), 118 OperandType::kUImm); 119 return GetUnsignedOperand(operand_index, OperandType::kUImm); 120 } 121 122 int32_t BytecodeArrayAccessor::GetImmediateOperand(int operand_index) const { 123 DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), 124 OperandType::kImm); 125 return GetSignedOperand(operand_index, OperandType::kImm); 126 } 127 128 uint32_t BytecodeArrayAccessor::GetRegisterCountOperand( 129 int operand_index) const { 130 DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), 131 OperandType::kRegCount); 132 return GetUnsignedOperand(operand_index, OperandType::kRegCount); 133 } 134 135 uint32_t BytecodeArrayAccessor::GetIndexOperand(int operand_index) const { 136 OperandType operand_type = 137 Bytecodes::GetOperandType(current_bytecode(), operand_index); 138 DCHECK_EQ(operand_type, OperandType::kIdx); 139 return GetUnsignedOperand(operand_index, operand_type); 140 } 141 142 FeedbackSlot BytecodeArrayAccessor::GetSlotOperand(int operand_index) const { 143 int index = GetIndexOperand(operand_index); 144 return FeedbackVector::ToSlot(index); 145 } 146 147 Register BytecodeArrayAccessor::GetRegisterOperand(int operand_index) const { 148 OperandType operand_type = 149 Bytecodes::GetOperandType(current_bytecode(), operand_index); 150 Address operand_start = 151 bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ + 152 current_prefix_offset() + 153 Bytecodes::GetOperandOffset(current_bytecode(), operand_index, 154 current_operand_scale()); 155 return BytecodeDecoder::DecodeRegisterOperand(operand_start, operand_type, 156 current_operand_scale()); 157 } 158 159 int BytecodeArrayAccessor::GetRegisterOperandRange(int operand_index) const { 160 DCHECK_LE(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); 161 const OperandType* operand_types = 162 Bytecodes::GetOperandTypes(current_bytecode()); 163 OperandType operand_type = operand_types[operand_index]; 164 DCHECK(Bytecodes::IsRegisterOperandType(operand_type)); 165 if (operand_type == OperandType::kRegList || 166 operand_type == OperandType::kRegOutList) { 167 return GetRegisterCountOperand(operand_index + 1); 168 } else { 169 return Bytecodes::GetNumberOfRegistersRepresentedBy(operand_type); 170 } 171 } 172 173 Runtime::FunctionId BytecodeArrayAccessor::GetRuntimeIdOperand( 174 int operand_index) const { 175 OperandType operand_type = 176 Bytecodes::GetOperandType(current_bytecode(), operand_index); 177 DCHECK_EQ(operand_type, OperandType::kRuntimeId); 178 uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type); 179 return static_cast<Runtime::FunctionId>(raw_id); 180 } 181 182 uint32_t BytecodeArrayAccessor::GetNativeContextIndexOperand( 183 int operand_index) const { 184 OperandType operand_type = 185 Bytecodes::GetOperandType(current_bytecode(), operand_index); 186 DCHECK_EQ(operand_type, OperandType::kNativeContextIndex); 187 return GetUnsignedOperand(operand_index, operand_type); 188 } 189 190 Runtime::FunctionId BytecodeArrayAccessor::GetIntrinsicIdOperand( 191 int operand_index) const { 192 OperandType operand_type = 193 Bytecodes::GetOperandType(current_bytecode(), operand_index); 194 DCHECK_EQ(operand_type, OperandType::kIntrinsicId); 195 uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type); 196 return IntrinsicsHelper::ToRuntimeId( 197 static_cast<IntrinsicsHelper::IntrinsicId>(raw_id)); 198 } 199 200 Object* BytecodeArrayAccessor::GetConstantAtIndex(int index) const { 201 return bytecode_array()->constant_pool()->get(index); 202 } 203 204 Object* BytecodeArrayAccessor::GetConstantForIndexOperand( 205 int operand_index) const { 206 return GetConstantAtIndex(GetIndexOperand(operand_index)); 207 } 208 209 int BytecodeArrayAccessor::GetJumpTargetOffset() const { 210 Bytecode bytecode = current_bytecode(); 211 if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) { 212 int relative_offset = GetUnsignedImmediateOperand(0); 213 if (bytecode == Bytecode::kJumpLoop) { 214 relative_offset = -relative_offset; 215 } 216 return GetAbsoluteOffset(relative_offset); 217 } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) { 218 Smi* smi = Smi::cast(GetConstantForIndexOperand(0)); 219 return GetAbsoluteOffset(smi->value()); 220 } else { 221 UNREACHABLE(); 222 } 223 } 224 225 JumpTableTargetOffsets BytecodeArrayAccessor::GetJumpTableTargetOffsets() 226 const { 227 uint32_t table_start, table_size; 228 int32_t case_value_base; 229 if (current_bytecode() == Bytecode::kSwitchOnGeneratorState) { 230 table_start = GetIndexOperand(1); 231 table_size = GetUnsignedImmediateOperand(2); 232 case_value_base = 0; 233 } else { 234 DCHECK_EQ(current_bytecode(), Bytecode::kSwitchOnSmiNoFeedback); 235 table_start = GetIndexOperand(0); 236 table_size = GetUnsignedImmediateOperand(1); 237 case_value_base = GetImmediateOperand(2); 238 } 239 return JumpTableTargetOffsets(this, table_start, table_size, case_value_base); 240 } 241 242 int BytecodeArrayAccessor::GetAbsoluteOffset(int relative_offset) const { 243 return current_offset() + relative_offset + current_prefix_offset(); 244 } 245 246 bool BytecodeArrayAccessor::OffsetWithinBytecode(int offset) const { 247 return current_offset() <= offset && 248 offset < current_offset() + current_bytecode_size(); 249 } 250 251 std::ostream& BytecodeArrayAccessor::PrintTo(std::ostream& os) const { 252 const uint8_t* bytecode_addr = reinterpret_cast<const uint8_t*>( 253 bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_); 254 return BytecodeDecoder::Decode(os, bytecode_addr, 255 bytecode_array()->parameter_count()); 256 } 257 258 JumpTableTargetOffsets::JumpTableTargetOffsets( 259 const BytecodeArrayAccessor* accessor, int table_start, int table_size, 260 int case_value_base) 261 : accessor_(accessor), 262 table_start_(table_start), 263 table_size_(table_size), 264 case_value_base_(case_value_base) {} 265 266 JumpTableTargetOffsets::iterator JumpTableTargetOffsets::begin() const { 267 return iterator(case_value_base_, table_start_, table_start_ + table_size_, 268 accessor_); 269 } 270 JumpTableTargetOffsets::iterator JumpTableTargetOffsets::end() const { 271 return iterator(case_value_base_ + table_size_, table_start_ + table_size_, 272 table_start_ + table_size_, accessor_); 273 } 274 int JumpTableTargetOffsets::size() const { 275 int ret = 0; 276 // TODO(leszeks): Is there a more efficient way of doing this than iterating? 277 for (const auto& entry : *this) { 278 USE(entry); 279 ret++; 280 } 281 return ret; 282 } 283 284 JumpTableTargetOffsets::iterator::iterator( 285 int case_value, int table_offset, int table_end, 286 const BytecodeArrayAccessor* accessor) 287 : accessor_(accessor), 288 current_(Smi::kZero), 289 index_(case_value), 290 table_offset_(table_offset), 291 table_end_(table_end) { 292 UpdateAndAdvanceToValid(); 293 } 294 295 JumpTableTargetOffset JumpTableTargetOffsets::iterator::operator*() { 296 DCHECK_LT(table_offset_, table_end_); 297 return {index_, accessor_->GetAbsoluteOffset(Smi::ToInt(current_))}; 298 } 299 300 JumpTableTargetOffsets::iterator& JumpTableTargetOffsets::iterator:: 301 operator++() { 302 DCHECK_LT(table_offset_, table_end_); 303 ++table_offset_; 304 ++index_; 305 UpdateAndAdvanceToValid(); 306 return *this; 307 } 308 309 bool JumpTableTargetOffsets::iterator::operator!=( 310 const JumpTableTargetOffsets::iterator& other) { 311 DCHECK_EQ(accessor_, other.accessor_); 312 DCHECK_EQ(table_end_, other.table_end_); 313 DCHECK_EQ(index_ - other.index_, table_offset_ - other.table_offset_); 314 return index_ != other.index_; 315 } 316 317 void JumpTableTargetOffsets::iterator::UpdateAndAdvanceToValid() { 318 if (table_offset_ >= table_end_) return; 319 320 Object* current = accessor_->GetConstantAtIndex(table_offset_); 321 while (!current->IsSmi()) { 322 DCHECK(current->IsTheHole()); 323 ++table_offset_; 324 ++index_; 325 if (table_offset_ >= table_end_) break; 326 current = accessor_->GetConstantAtIndex(table_offset_); 327 } 328 // Make sure we haven't reached the end of the table with a hole in current. 329 if (current->IsSmi()) { 330 current_ = Smi::cast(current); 331 } 332 } 333 334 } // namespace interpreter 335 } // namespace internal 336 } // namespace v8 337