bytecode-array-accessor.cc 14.4 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright 2015 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.

#include "src/interpreter/bytecode-array-accessor.h"

#include "src/interpreter/bytecode-decoder.h"
#include "src/interpreter/interpreter-intrinsics.h"
9
#include "src/objects/code-inl.h"
10 11
#include "src/objects/feedback-vector.h"
#include "src/objects/objects-inl.h"
12 13 14 15 16

namespace v8 {
namespace internal {
namespace interpreter {

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
namespace {

class OnHeapBytecodeArray final : public AbstractBytecodeArray {
 public:
  explicit OnHeapBytecodeArray(Handle<BytecodeArray> bytecode_array)
      : array_(bytecode_array) {}

  int length() const override { return array_->length(); }

  int parameter_count() const override { return array_->parameter_count(); }

  uint8_t get(int index) const override { return array_->get(index); }

  void set(int index, uint8_t value) override {
    return array_->set(index, value);
  }

  Address GetFirstBytecodeAddress() const override {
    return array_->GetFirstBytecodeAddress();
  }

  Handle<Object> GetConstantAtIndex(int index,
                                    Isolate* isolate) const override {
    return handle(array_->constant_pool().get(index), isolate);
  }

  bool IsConstantAtIndexSmi(int index) const override {
    return array_->constant_pool().get(index).IsSmi();
  }

  Smi GetConstantAtIndexAsSmi(int index) const override {
    return Smi::cast(array_->constant_pool().get(index));
  }

 private:
  Handle<BytecodeArray> array_;
};

}  // namespace

57
BytecodeArrayAccessor::BytecodeArrayAccessor(
58 59
    std::unique_ptr<AbstractBytecodeArray> bytecode_array, int initial_offset)
    : bytecode_array_(std::move(bytecode_array)),
60 61 62 63 64 65
      bytecode_offset_(initial_offset),
      operand_scale_(OperandScale::kSingle),
      prefix_offset_(0) {
  UpdateOperandScale();
}

66 67
BytecodeArrayAccessor::BytecodeArrayAccessor(
    Handle<BytecodeArray> bytecode_array, int initial_offset)
68
    : BytecodeArrayAccessor(
69
          std::make_unique<OnHeapBytecodeArray>(bytecode_array),
70
          initial_offset) {}
71

72 73 74 75 76
void BytecodeArrayAccessor::SetOffset(int offset) {
  bytecode_offset_ = offset;
  UpdateOperandScale();
}

77 78 79 80 81
void BytecodeArrayAccessor::ApplyDebugBreak() {
  // Get the raw bytecode from the bytecode array. This may give us a
  // scaling prefix, which we can patch with the matching debug-break
  // variant.
  interpreter::Bytecode bytecode =
82
      interpreter::Bytecodes::FromByte(bytecode_array()->get(bytecode_offset_));
83 84 85
  if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return;
  interpreter::Bytecode debugbreak =
      interpreter::Bytecodes::GetDebugBreak(bytecode);
86 87
  bytecode_array()->set(bytecode_offset_,
                        interpreter::Bytecodes::ToByte(debugbreak));
88 89
}

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
void BytecodeArrayAccessor::UpdateOperandScale() {
  if (OffsetInBounds()) {
    uint8_t current_byte = bytecode_array()->get(bytecode_offset_);
    Bytecode current_bytecode = Bytecodes::FromByte(current_byte);
    if (Bytecodes::IsPrefixScalingBytecode(current_bytecode)) {
      operand_scale_ =
          Bytecodes::PrefixBytecodeToOperandScale(current_bytecode);
      prefix_offset_ = 1;
    } else {
      operand_scale_ = OperandScale::kSingle;
      prefix_offset_ = 0;
    }
  }
}

bool BytecodeArrayAccessor::OffsetInBounds() const {
  return bytecode_offset_ >= 0 && bytecode_offset_ < bytecode_array()->length();
}

Bytecode BytecodeArrayAccessor::current_bytecode() const {
  DCHECK(OffsetInBounds());
  uint8_t current_byte =
      bytecode_array()->get(bytecode_offset_ + current_prefix_offset());
  Bytecode current_bytecode = Bytecodes::FromByte(current_byte);
  DCHECK(!Bytecodes::IsPrefixScalingBytecode(current_bytecode));
  return current_bytecode;
}

int BytecodeArrayAccessor::current_bytecode_size() const {
  return current_prefix_offset() +
         Bytecodes::Size(current_bytecode(), current_operand_scale());
}

uint32_t BytecodeArrayAccessor::GetUnsignedOperand(
    int operand_index, OperandType operand_type) const {
  DCHECK_GE(operand_index, 0);
  DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
  DCHECK_EQ(operand_type,
            Bytecodes::GetOperandType(current_bytecode(), operand_index));
  DCHECK(Bytecodes::IsUnsignedOperandType(operand_type));
130
  Address operand_start =
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
      bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ +
      current_prefix_offset() +
      Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
                                  current_operand_scale());
  return BytecodeDecoder::DecodeUnsignedOperand(operand_start, operand_type,
                                                current_operand_scale());
}

int32_t BytecodeArrayAccessor::GetSignedOperand(
    int operand_index, OperandType operand_type) const {
  DCHECK_GE(operand_index, 0);
  DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
  DCHECK_EQ(operand_type,
            Bytecodes::GetOperandType(current_bytecode(), operand_index));
  DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type));
146
  Address operand_start =
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
      bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ +
      current_prefix_offset() +
      Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
                                  current_operand_scale());
  return BytecodeDecoder::DecodeSignedOperand(operand_start, operand_type,
                                              current_operand_scale());
}

uint32_t BytecodeArrayAccessor::GetFlagOperand(int operand_index) const {
  DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
            OperandType::kFlag8);
  return GetUnsignedOperand(operand_index, OperandType::kFlag8);
}

uint32_t BytecodeArrayAccessor::GetUnsignedImmediateOperand(
    int operand_index) const {
  DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
            OperandType::kUImm);
  return GetUnsignedOperand(operand_index, OperandType::kUImm);
}

int32_t BytecodeArrayAccessor::GetImmediateOperand(int operand_index) const {
  DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
            OperandType::kImm);
  return GetSignedOperand(operand_index, OperandType::kImm);
}

uint32_t BytecodeArrayAccessor::GetRegisterCountOperand(
    int operand_index) const {
  DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
            OperandType::kRegCount);
  return GetUnsignedOperand(operand_index, OperandType::kRegCount);
}

uint32_t BytecodeArrayAccessor::GetIndexOperand(int operand_index) const {
  OperandType operand_type =
      Bytecodes::GetOperandType(current_bytecode(), operand_index);
  DCHECK_EQ(operand_type, OperandType::kIdx);
  return GetUnsignedOperand(operand_index, operand_type);
}

188 189 190 191 192
FeedbackSlot BytecodeArrayAccessor::GetSlotOperand(int operand_index) const {
  int index = GetIndexOperand(operand_index);
  return FeedbackVector::ToSlot(index);
}

193 194 195 196 197 198 199 200 201 202 203 204
Register BytecodeArrayAccessor::GetReceiver() const {
  return Register::FromParameterIndex(0, bytecode_array()->parameter_count());
}

Register BytecodeArrayAccessor::GetParameter(int parameter_index) const {
  DCHECK_GE(parameter_index, 0);
  // The parameter indices are shifted by 1 (receiver is the
  // first entry).
  return Register::FromParameterIndex(parameter_index + 1,
                                      bytecode_array()->parameter_count());
}

205 206 207
Register BytecodeArrayAccessor::GetRegisterOperand(int operand_index) const {
  OperandType operand_type =
      Bytecodes::GetOperandType(current_bytecode(), operand_index);
208
  Address operand_start =
209 210 211 212 213 214 215 216 217 218 219 220 221 222
      bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ +
      current_prefix_offset() +
      Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
                                  current_operand_scale());
  return BytecodeDecoder::DecodeRegisterOperand(operand_start, operand_type,
                                                current_operand_scale());
}

int BytecodeArrayAccessor::GetRegisterOperandRange(int operand_index) const {
  DCHECK_LE(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
  const OperandType* operand_types =
      Bytecodes::GetOperandTypes(current_bytecode());
  OperandType operand_type = operand_types[operand_index];
  DCHECK(Bytecodes::IsRegisterOperandType(operand_type));
223 224
  if (operand_type == OperandType::kRegList ||
      operand_type == OperandType::kRegOutList) {
225 226 227 228 229 230 231 232 233 234
    return GetRegisterCountOperand(operand_index + 1);
  } else {
    return Bytecodes::GetNumberOfRegistersRepresentedBy(operand_type);
  }
}

Runtime::FunctionId BytecodeArrayAccessor::GetRuntimeIdOperand(
    int operand_index) const {
  OperandType operand_type =
      Bytecodes::GetOperandType(current_bytecode(), operand_index);
235
  DCHECK_EQ(operand_type, OperandType::kRuntimeId);
236 237 238 239
  uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type);
  return static_cast<Runtime::FunctionId>(raw_id);
}

240 241 242 243
uint32_t BytecodeArrayAccessor::GetNativeContextIndexOperand(
    int operand_index) const {
  OperandType operand_type =
      Bytecodes::GetOperandType(current_bytecode(), operand_index);
244
  DCHECK_EQ(operand_type, OperandType::kNativeContextIndex);
245 246 247
  return GetUnsignedOperand(operand_index, operand_type);
}

248 249 250 251
Runtime::FunctionId BytecodeArrayAccessor::GetIntrinsicIdOperand(
    int operand_index) const {
  OperandType operand_type =
      Bytecodes::GetOperandType(current_bytecode(), operand_index);
252
  DCHECK_EQ(operand_type, OperandType::kIntrinsicId);
253 254 255 256 257
  uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type);
  return IntrinsicsHelper::ToRuntimeId(
      static_cast<IntrinsicsHelper::IntrinsicId>(raw_id));
}

258 259
Handle<Object> BytecodeArrayAccessor::GetConstantAtIndex(
    int index, Isolate* isolate) const {
260
  return bytecode_array()->GetConstantAtIndex(index, isolate);
261 262
}

263
bool BytecodeArrayAccessor::IsConstantAtIndexSmi(int index) const {
264
  return bytecode_array()->IsConstantAtIndexSmi(index);
265 266 267
}

Smi BytecodeArrayAccessor::GetConstantAtIndexAsSmi(int index) const {
268
  return bytecode_array()->GetConstantAtIndexAsSmi(index);
269 270 271 272 273
}

Handle<Object> BytecodeArrayAccessor::GetConstantForIndexOperand(
    int operand_index, Isolate* isolate) const {
  return GetConstantAtIndex(GetIndexOperand(operand_index), isolate);
274 275
}

276
int BytecodeArrayAccessor::GetRelativeJumpTargetOffset() const {
277 278
  Bytecode bytecode = current_bytecode();
  if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) {
279 280 281 282
    int relative_offset = GetUnsignedImmediateOperand(0);
    if (bytecode == Bytecode::kJumpLoop) {
      relative_offset = -relative_offset;
    }
283
    return relative_offset;
284
  } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) {
285
    Smi smi = GetConstantAtIndexAsSmi(GetIndexOperand(0));
286
    return smi.value();
287 288 289 290 291
  } else {
    UNREACHABLE();
  }
}

292 293 294 295
int BytecodeArrayAccessor::GetJumpTargetOffset() const {
  return GetAbsoluteOffset(GetRelativeJumpTargetOffset());
}

296 297
JumpTableTargetOffsets BytecodeArrayAccessor::GetJumpTableTargetOffsets()
    const {
298 299 300 301 302 303 304 305 306 307 308 309
  uint32_t table_start, table_size;
  int32_t case_value_base;
  if (current_bytecode() == Bytecode::kSwitchOnGeneratorState) {
    table_start = GetIndexOperand(1);
    table_size = GetUnsignedImmediateOperand(2);
    case_value_base = 0;
  } else {
    DCHECK_EQ(current_bytecode(), Bytecode::kSwitchOnSmiNoFeedback);
    table_start = GetIndexOperand(0);
    table_size = GetUnsignedImmediateOperand(1);
    case_value_base = GetImmediateOperand(2);
  }
310 311 312 313 314 315 316
  return JumpTableTargetOffsets(this, table_start, table_size, case_value_base);
}

int BytecodeArrayAccessor::GetAbsoluteOffset(int relative_offset) const {
  return current_offset() + relative_offset + current_prefix_offset();
}

317 318 319 320 321
bool BytecodeArrayAccessor::OffsetWithinBytecode(int offset) const {
  return current_offset() <= offset &&
         offset < current_offset() + current_bytecode_size();
}

322
std::ostream& BytecodeArrayAccessor::PrintTo(std::ostream& os) const {
323 324 325 326
  const uint8_t* bytecode_addr = reinterpret_cast<const uint8_t*>(
      bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_);
  return BytecodeDecoder::Decode(os, bytecode_addr,
                                 bytecode_array()->parameter_count());
327 328
}

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
JumpTableTargetOffsets::JumpTableTargetOffsets(
    const BytecodeArrayAccessor* accessor, int table_start, int table_size,
    int case_value_base)
    : accessor_(accessor),
      table_start_(table_start),
      table_size_(table_size),
      case_value_base_(case_value_base) {}

JumpTableTargetOffsets::iterator JumpTableTargetOffsets::begin() const {
  return iterator(case_value_base_, table_start_, table_start_ + table_size_,
                  accessor_);
}
JumpTableTargetOffsets::iterator JumpTableTargetOffsets::end() const {
  return iterator(case_value_base_ + table_size_, table_start_ + table_size_,
                  table_start_ + table_size_, accessor_);
}
345 346 347 348 349 350 351 352 353
int JumpTableTargetOffsets::size() const {
  int ret = 0;
  // TODO(leszeks): Is there a more efficient way of doing this than iterating?
  for (const auto& entry : *this) {
    USE(entry);
    ret++;
  }
  return ret;
}
354 355 356 357 358

JumpTableTargetOffsets::iterator::iterator(
    int case_value, int table_offset, int table_end,
    const BytecodeArrayAccessor* accessor)
    : accessor_(accessor),
359
      current_(Smi::zero()),
360 361 362 363 364 365 366 367
      index_(case_value),
      table_offset_(table_offset),
      table_end_(table_end) {
  UpdateAndAdvanceToValid();
}

JumpTableTargetOffset JumpTableTargetOffsets::iterator::operator*() {
  DCHECK_LT(table_offset_, table_end_);
368
  return {index_, accessor_->GetAbsoluteOffset(Smi::ToInt(current_))};
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
}

JumpTableTargetOffsets::iterator& JumpTableTargetOffsets::iterator::
operator++() {
  DCHECK_LT(table_offset_, table_end_);
  ++table_offset_;
  ++index_;
  UpdateAndAdvanceToValid();
  return *this;
}

bool JumpTableTargetOffsets::iterator::operator!=(
    const JumpTableTargetOffsets::iterator& other) {
  DCHECK_EQ(accessor_, other.accessor_);
  DCHECK_EQ(table_end_, other.table_end_);
  DCHECK_EQ(index_ - other.index_, table_offset_ - other.table_offset_);
  return index_ != other.index_;
}

void JumpTableTargetOffsets::iterator::UpdateAndAdvanceToValid() {
389 390
  while (table_offset_ < table_end_ &&
         !accessor_->IsConstantAtIndexSmi(table_offset_)) {
391 392
    ++table_offset_;
    ++index_;
393
  }
394

395
  // Make sure we haven't reached the end of the table with a hole in current.
396 397 398
  if (table_offset_ < table_end_) {
    DCHECK(accessor_->IsConstantAtIndexSmi(table_offset_));
    current_ = accessor_->GetConstantAtIndexAsSmi(table_offset_);
399 400 401
  }
}

402 403 404
}  // namespace interpreter
}  // namespace internal
}  // namespace v8