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