bytecode-array-accessor.cc 14 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
namespace {

class OnHeapBytecodeArray final : public AbstractBytecodeArray {
 public:
  explicit OnHeapBytecodeArray(Handle<BytecodeArray> bytecode_array)
22
      : AbstractBytecodeArray(), array_(bytecode_array) {}
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

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

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

  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

51 52 53 54 55 56 57 58
// TODO(verwaest): Pass the LocalHeap into the constructor.
AbstractBytecodeArray::AbstractBytecodeArray()
    : local_heap_(LocalHeap::Current()) {
  if (!local_heap_) {
    local_heap_ = Isolate::Current()->main_thread_local_heap();
  }
}

59
BytecodeArrayAccessor::BytecodeArrayAccessor(
60 61
    std::unique_ptr<AbstractBytecodeArray> bytecode_array, int initial_offset)
    : bytecode_array_(std::move(bytecode_array)),
62 63 64 65
      start_(reinterpret_cast<uint8_t*>(
          bytecode_array_->GetFirstBytecodeAddress())),
      end_(start_ + bytecode_array_->length()),
      cursor_(start_ + initial_offset),
66
      operand_scale_(OperandScale::kSingle),
67 68 69
      prefix_size_(0) {
  bytecode_array_->local_heap()->AddGCEpilogueCallback(UpdatePointersCallback,
                                                       this);
70 71 72
  UpdateOperandScale();
}

73 74
BytecodeArrayAccessor::BytecodeArrayAccessor(
    Handle<BytecodeArray> bytecode_array, int initial_offset)
75
    : BytecodeArrayAccessor(
76
          std::make_unique<OnHeapBytecodeArray>(bytecode_array),
77
          initial_offset) {}
78

79 80 81 82 83
BytecodeArrayAccessor::~BytecodeArrayAccessor() {
  bytecode_array_->local_heap()->RemoveGCEpilogueCallback(
      UpdatePointersCallback, this);
}

84
void BytecodeArrayAccessor::SetOffset(int offset) {
85 86 87
  if (offset < 0) return;
  cursor_ = reinterpret_cast<uint8_t*>(
      bytecode_array()->GetFirstBytecodeAddress() + offset);
88 89 90
  UpdateOperandScale();
}

91 92 93 94
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.
95 96
  uint8_t* cursor = cursor_ - prefix_size_;
  interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(*cursor);
97 98 99
  if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return;
  interpreter::Bytecode debugbreak =
      interpreter::Bytecodes::GetDebugBreak(bytecode);
100
  *cursor = interpreter::Bytecodes::ToByte(debugbreak);
101 102 103
}

int BytecodeArrayAccessor::current_bytecode_size() const {
104
  return prefix_size_ +
105 106 107 108 109 110 111 112 113 114
         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));
115
  Address operand_start =
116
      reinterpret_cast<Address>(cursor_) +
117 118 119 120 121 122 123 124 125 126 127 128 129
      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));
130
  Address operand_start =
131
      reinterpret_cast<Address>(cursor_) +
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
      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);
}

171 172 173 174 175
FeedbackSlot BytecodeArrayAccessor::GetSlotOperand(int operand_index) const {
  int index = GetIndexOperand(operand_index);
  return FeedbackVector::ToSlot(index);
}

176 177 178 179 180 181 182 183 184 185 186 187
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());
}

188 189 190
Register BytecodeArrayAccessor::GetRegisterOperand(int operand_index) const {
  OperandType operand_type =
      Bytecodes::GetOperandType(current_bytecode(), operand_index);
191
  Address operand_start =
192
      reinterpret_cast<Address>(cursor_) +
193 194 195 196 197 198
      Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
                                  current_operand_scale());
  return BytecodeDecoder::DecodeRegisterOperand(operand_start, operand_type,
                                                current_operand_scale());
}

199 200 201 202 203 204 205 206 207 208 209 210 211 212
std::pair<Register, Register> BytecodeArrayAccessor::GetRegisterPairOperand(
    int operand_index) const {
  Register first = GetRegisterOperand(operand_index);
  Register second(first.index() + 1);
  return std::make_pair(first, second);
}

RegisterList BytecodeArrayAccessor::GetRegisterListOperand(
    int operand_index) const {
  Register first = GetRegisterOperand(operand_index);
  uint32_t count = GetRegisterCountOperand(operand_index + 1);
  return RegisterList(first.index(), count);
}

213 214 215 216 217 218
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));
219 220
  if (operand_type == OperandType::kRegList ||
      operand_type == OperandType::kRegOutList) {
221 222 223 224 225 226 227 228 229 230
    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);
231
  DCHECK_EQ(operand_type, OperandType::kRuntimeId);
232 233 234 235
  uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type);
  return static_cast<Runtime::FunctionId>(raw_id);
}

236 237 238 239
uint32_t BytecodeArrayAccessor::GetNativeContextIndexOperand(
    int operand_index) const {
  OperandType operand_type =
      Bytecodes::GetOperandType(current_bytecode(), operand_index);
240
  DCHECK_EQ(operand_type, OperandType::kNativeContextIndex);
241 242 243
  return GetUnsignedOperand(operand_index, operand_type);
}

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

254 255
Handle<Object> BytecodeArrayAccessor::GetConstantAtIndex(
    int index, Isolate* isolate) const {
256
  return bytecode_array()->GetConstantAtIndex(index, isolate);
257 258
}

259
bool BytecodeArrayAccessor::IsConstantAtIndexSmi(int index) const {
260
  return bytecode_array()->IsConstantAtIndexSmi(index);
261 262 263
}

Smi BytecodeArrayAccessor::GetConstantAtIndexAsSmi(int index) const {
264
  return bytecode_array()->GetConstantAtIndexAsSmi(index);
265 266 267 268 269
}

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

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

288 289 290 291
int BytecodeArrayAccessor::GetJumpTargetOffset() const {
  return GetAbsoluteOffset(GetRelativeJumpTargetOffset());
}

292 293
JumpTableTargetOffsets BytecodeArrayAccessor::GetJumpTableTargetOffsets()
    const {
294 295 296 297 298 299 300 301 302 303 304 305
  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);
  }
306 307 308 309
  return JumpTableTargetOffsets(this, table_start, table_size, case_value_base);
}

int BytecodeArrayAccessor::GetAbsoluteOffset(int relative_offset) const {
310
  return current_offset() + relative_offset + prefix_size_;
311 312
}

313
std::ostream& BytecodeArrayAccessor::PrintTo(std::ostream& os) const {
314
  return BytecodeDecoder::Decode(os, cursor_ - prefix_size_,
315
                                 bytecode_array()->parameter_count());
316 317
}

318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
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_);
}
334 335 336 337 338 339 340 341 342
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;
}
343 344 345 346 347

JumpTableTargetOffsets::iterator::iterator(
    int case_value, int table_offset, int table_end,
    const BytecodeArrayAccessor* accessor)
    : accessor_(accessor),
348
      current_(Smi::zero()),
349 350 351 352 353 354 355 356
      index_(case_value),
      table_offset_(table_offset),
      table_end_(table_end) {
  UpdateAndAdvanceToValid();
}

JumpTableTargetOffset JumpTableTargetOffsets::iterator::operator*() {
  DCHECK_LT(table_offset_, table_end_);
357
  return {index_, accessor_->GetAbsoluteOffset(Smi::ToInt(current_))};
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
}

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() {
378 379
  while (table_offset_ < table_end_ &&
         !accessor_->IsConstantAtIndexSmi(table_offset_)) {
380 381
    ++table_offset_;
    ++index_;
382
  }
383

384
  // Make sure we haven't reached the end of the table with a hole in current.
385 386 387
  if (table_offset_ < table_end_) {
    DCHECK(accessor_->IsConstantAtIndexSmi(table_offset_));
    current_ = accessor_->GetConstantAtIndexAsSmi(table_offset_);
388 389 390
  }
}

391 392 393
}  // namespace interpreter
}  // namespace internal
}  // namespace v8