• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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