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