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
11 namespace v8 {
12 namespace internal {
13 namespace interpreter {
14
15 // static
DecodeRegisterOperand(const uint8_t * operand_start,OperandType operand_type,OperandScale operand_scale)16 Register 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
DecodeRegisterListOperand(const uint8_t * operand_start,uint32_t count,OperandType operand_type,OperandScale operand_scale)26 RegisterList 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
DecodeSignedOperand(const uint8_t * operand_start,OperandType operand_type,OperandScale operand_scale)35 int32_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
DecodeUnsignedOperand(const uint8_t * operand_start,OperandType operand_type,OperandScale operand_scale)53 uint32_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
70 namespace {
NameForRuntimeId(uint32_t idx)71 const 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
Decode(std::ostream & os,const uint8_t * bytecode_start,int parameter_count)88 std::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