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