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-decoder.h"
6
7#include <iomanip>
8
9#include "src/interpreter/interpreter-intrinsics.h"
10
11namespace v8 {
12namespace internal {
13namespace interpreter {
14
15// static
16Register BytecodeDecoder::DecodeRegisterOperand(const uint8_t* operand_start,
17                                                OperandType operand_type,
18                                                OperandScale operand_scale) {
19  DCHECK(Bytecodes::IsRegisterOperandType(operand_type));
20  int32_t operand =
21      DecodeSignedOperand(operand_start, operand_type, operand_scale);
22  return Register::FromOperand(operand);
23}
24
25// static
26RegisterList BytecodeDecoder::DecodeRegisterListOperand(
27    const uint8_t* operand_start, uint32_t count, OperandType operand_type,
28    OperandScale operand_scale) {
29  Register first_reg =
30      DecodeRegisterOperand(operand_start, operand_type, operand_scale);
31  return RegisterList(first_reg.index(), static_cast<int>(count));
32}
33
34// static
35int32_t BytecodeDecoder::DecodeSignedOperand(const uint8_t* operand_start,
36                                             OperandType operand_type,
37                                             OperandScale operand_scale) {
38  DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type));
39  switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) {
40    case OperandSize::kByte:
41      return static_cast<int8_t>(*operand_start);
42    case OperandSize::kShort:
43      return static_cast<int16_t>(ReadUnalignedUInt16(operand_start));
44    case OperandSize::kQuad:
45      return static_cast<int32_t>(ReadUnalignedUInt32(operand_start));
46    case OperandSize::kNone:
47      UNREACHABLE();
48  }
49  return 0;
50}
51
52// static
53uint32_t BytecodeDecoder::DecodeUnsignedOperand(const uint8_t* operand_start,
54                                                OperandType operand_type,
55                                                OperandScale operand_scale) {
56  DCHECK(Bytecodes::IsUnsignedOperandType(operand_type));
57  switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) {
58    case OperandSize::kByte:
59      return *operand_start;
60    case OperandSize::kShort:
61      return ReadUnalignedUInt16(operand_start);
62    case OperandSize::kQuad:
63      return ReadUnalignedUInt32(operand_start);
64    case OperandSize::kNone:
65      UNREACHABLE();
66  }
67  return 0;
68}
69
70namespace {
71const char* NameForRuntimeId(uint32_t idx) {
72  switch (idx) {
73#define CASE(name, nargs, ressize) \
74  case Runtime::k##name:           \
75    return #name;                  \
76  case Runtime::kInline##name:     \
77    return #name;
78    FOR_EACH_INTRINSIC(CASE)
79#undef CASE
80    default:
81      UNREACHABLE();
82      return nullptr;
83  }
84}
85}  // anonymous namespace
86
87// static
88std::ostream& BytecodeDecoder::Decode(std::ostream& os,
89                                      const uint8_t* bytecode_start,
90                                      int parameter_count) {
91  Bytecode bytecode = Bytecodes::FromByte(bytecode_start[0]);
92  int prefix_offset = 0;
93  OperandScale operand_scale = OperandScale::kSingle;
94  if (Bytecodes::IsPrefixScalingBytecode(bytecode)) {
95    prefix_offset = 1;
96    operand_scale = Bytecodes::PrefixBytecodeToOperandScale(bytecode);
97    bytecode = Bytecodes::FromByte(bytecode_start[1]);
98  }
99
100  // Prepare to print bytecode and operands as hex digits.
101  std::ios saved_format(nullptr);
102  saved_format.copyfmt(saved_format);
103  os.fill('0');
104  os.flags(std::ios::hex);
105
106  int bytecode_size = Bytecodes::Size(bytecode, operand_scale);
107  for (int i = 0; i < prefix_offset + bytecode_size; i++) {
108    os << std::setw(2) << static_cast<uint32_t>(bytecode_start[i]) << ' ';
109  }
110  os.copyfmt(saved_format);
111
112  const int kBytecodeColumnSize = 6;
113  for (int i = prefix_offset + bytecode_size; i < kBytecodeColumnSize; i++) {
114    os << "   ";
115  }
116
117  os << Bytecodes::ToString(bytecode, operand_scale) << " ";
118
119  // Operands for the debug break are from the original instruction.
120  if (Bytecodes::IsDebugBreak(bytecode)) return os;
121
122  int number_of_operands = Bytecodes::NumberOfOperands(bytecode);
123  for (int i = 0; i < number_of_operands; i++) {
124    OperandType op_type = Bytecodes::GetOperandType(bytecode, i);
125    int operand_offset =
126        Bytecodes::GetOperandOffset(bytecode, i, operand_scale);
127    const uint8_t* operand_start =
128        &bytecode_start[prefix_offset + operand_offset];
129    switch (op_type) {
130      case interpreter::OperandType::kIdx:
131      case interpreter::OperandType::kUImm:
132        os << "["
133           << DecodeUnsignedOperand(operand_start, op_type, operand_scale)
134           << "]";
135        break;
136      case interpreter::OperandType::kIntrinsicId: {
137        auto id = static_cast<IntrinsicsHelper::IntrinsicId>(
138            DecodeUnsignedOperand(operand_start, op_type, operand_scale));
139        os << "[" << NameForRuntimeId(IntrinsicsHelper::ToRuntimeId(id)) << "]";
140        break;
141      }
142      case interpreter::OperandType::kRuntimeId:
143        os << "[" << NameForRuntimeId(DecodeUnsignedOperand(
144                         operand_start, op_type, operand_scale))
145           << "]";
146        break;
147      case interpreter::OperandType::kImm:
148        os << "[" << DecodeSignedOperand(operand_start, op_type, operand_scale)
149           << "]";
150        break;
151      case interpreter::OperandType::kFlag8:
152        os << "#"
153           << DecodeUnsignedOperand(operand_start, op_type, operand_scale);
154        break;
155      case interpreter::OperandType::kReg:
156      case interpreter::OperandType::kRegOut: {
157        Register reg =
158            DecodeRegisterOperand(operand_start, op_type, operand_scale);
159        os << reg.ToString(parameter_count);
160        break;
161      }
162      case interpreter::OperandType::kRegOutTriple: {
163        RegisterList reg_list =
164            DecodeRegisterListOperand(operand_start, 3, op_type, operand_scale);
165        os << reg_list.first_register().ToString(parameter_count) << "-"
166           << reg_list.last_register().ToString(parameter_count);
167        break;
168      }
169      case interpreter::OperandType::kRegOutPair:
170      case interpreter::OperandType::kRegPair: {
171        RegisterList reg_list =
172            DecodeRegisterListOperand(operand_start, 2, op_type, operand_scale);
173        os << reg_list.first_register().ToString(parameter_count) << "-"
174           << reg_list.last_register().ToString(parameter_count);
175        break;
176      }
177      case interpreter::OperandType::kRegList: {
178        DCHECK_LT(i, number_of_operands - 1);
179        DCHECK_EQ(Bytecodes::GetOperandType(bytecode, i + 1),
180                  OperandType::kRegCount);
181        int reg_count_offset =
182            Bytecodes::GetOperandOffset(bytecode, i + 1, operand_scale);
183        const uint8_t* reg_count_operand =
184            &bytecode_start[prefix_offset + reg_count_offset];
185        uint32_t count = DecodeUnsignedOperand(
186            reg_count_operand, OperandType::kRegCount, operand_scale);
187        RegisterList reg_list = DecodeRegisterListOperand(
188            operand_start, count, op_type, operand_scale);
189        os << reg_list.first_register().ToString(parameter_count) << "-"
190           << reg_list.last_register().ToString(parameter_count);
191        i++;  // Skip kRegCount.
192        break;
193      }
194      case interpreter::OperandType::kNone:
195      case interpreter::OperandType::kRegCount:  // Dealt with in kRegList.
196        UNREACHABLE();
197        break;
198    }
199    if (i != number_of_operands - 1) {
200      os << ", ";
201    }
202  }
203  return os;
204}
205
206}  // namespace interpreter
207}  // namespace internal
208}  // namespace v8
209