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/bytecodes.h"
6
7#include <iomanip>
8
9#include "src/base/bits.h"
10#include "src/interpreter/bytecode-traits.h"
11
12namespace v8 {
13namespace internal {
14namespace interpreter {
15
16// clang-format off
17const OperandType* const Bytecodes::kOperandTypes[] = {
18#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kOperandTypes,
19  BYTECODE_LIST(ENTRY)
20#undef ENTRY
21};
22
23const OperandTypeInfo* const Bytecodes::kOperandTypeInfos[] = {
24#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kOperandTypeInfos,
25  BYTECODE_LIST(ENTRY)
26#undef ENTRY
27};
28
29const int Bytecodes::kOperandCount[] = {
30#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kOperandCount,
31  BYTECODE_LIST(ENTRY)
32#undef ENTRY
33};
34
35const ImplicitRegisterUse Bytecodes::kImplicitRegisterUse[] = {
36#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kImplicitRegisterUse,
37  BYTECODE_LIST(ENTRY)
38#undef ENTRY
39};
40
41const uint8_t Bytecodes::kBytecodeSizes[3][kBytecodeCount] = {
42  {
43#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kSingleScaleSize,
44  BYTECODE_LIST(ENTRY)
45#undef ENTRY
46  }, {
47#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kDoubleScaleSize,
48  BYTECODE_LIST(ENTRY)
49#undef ENTRY
50  }, {
51#define ENTRY(Name, ...) BytecodeTraits<__VA_ARGS__>::kQuadrupleScaleSize,
52  BYTECODE_LIST(ENTRY)
53#undef ENTRY
54  }
55};
56
57const OperandSize* const Bytecodes::kOperandSizes[3][kBytecodeCount] = {
58  {
59#define ENTRY(Name, ...)  \
60    BytecodeTraits<__VA_ARGS__>::kSingleScaleOperandSizes,
61  BYTECODE_LIST(ENTRY)
62#undef ENTRY
63  }, {
64#define ENTRY(Name, ...)  \
65    BytecodeTraits<__VA_ARGS__>::kDoubleScaleOperandSizes,
66  BYTECODE_LIST(ENTRY)
67#undef ENTRY
68  }, {
69#define ENTRY(Name, ...)  \
70    BytecodeTraits<__VA_ARGS__>::kQuadrupleScaleOperandSizes,
71  BYTECODE_LIST(ENTRY)
72#undef ENTRY
73  }
74};
75
76const OperandSize
77Bytecodes::kOperandKindSizes[3][BytecodeOperands::kOperandTypeCount] = {
78  {
79#define ENTRY(Name, ...)  \
80    OperandScaler<OperandType::k##Name, OperandScale::kSingle>::kOperandSize,
81  OPERAND_TYPE_LIST(ENTRY)
82#undef ENTRY
83  }, {
84#define ENTRY(Name, ...)  \
85    OperandScaler<OperandType::k##Name, OperandScale::kDouble>::kOperandSize,
86  OPERAND_TYPE_LIST(ENTRY)
87#undef ENTRY
88  }, {
89#define ENTRY(Name, ...)  \
90    OperandScaler<OperandType::k##Name, OperandScale::kQuadruple>::kOperandSize,
91  OPERAND_TYPE_LIST(ENTRY)
92#undef ENTRY
93  }
94};
95// clang-format on
96
97// Make sure kFirstShortStar and kLastShortStar are set correctly.
98#define ASSERT_SHORT_STAR_RANGE(Name, ...)                        \
99  STATIC_ASSERT(Bytecode::k##Name >= Bytecode::kFirstShortStar && \
100                Bytecode::k##Name <= Bytecode::kLastShortStar);
101SHORT_STAR_BYTECODE_LIST(ASSERT_SHORT_STAR_RANGE)
102#undef ASSERT_SHORT_STAR_RANGE
103
104// static
105const char* Bytecodes::ToString(Bytecode bytecode) {
106  switch (bytecode) {
107#define CASE(Name, ...)   \
108  case Bytecode::k##Name: \
109    return #Name;
110    BYTECODE_LIST(CASE)
111#undef CASE
112  }
113  UNREACHABLE();
114}
115
116// static
117std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale,
118                                const char* separator) {
119  std::string value(ToString(bytecode));
120  if (operand_scale > OperandScale::kSingle) {
121    Bytecode prefix_bytecode = OperandScaleToPrefixBytecode(operand_scale);
122    std::string suffix = ToString(prefix_bytecode);
123    return value.append(separator).append(suffix);
124  } else {
125    return value;
126  }
127}
128
129// static
130Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) {
131  DCHECK(!IsDebugBreak(bytecode));
132  if (bytecode == Bytecode::kWide) {
133    return Bytecode::kDebugBreakWide;
134  }
135  if (bytecode == Bytecode::kExtraWide) {
136    return Bytecode::kDebugBreakExtraWide;
137  }
138  int bytecode_size = Size(bytecode, OperandScale::kSingle);
139#define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name)                         \
140  if (bytecode_size == Size(Bytecode::k##Name, OperandScale::kSingle)) { \
141    return Bytecode::k##Name;                                            \
142  }
143  DEBUG_BREAK_PLAIN_BYTECODE_LIST(RETURN_IF_DEBUG_BREAK_SIZE_MATCHES)
144#undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES
145  UNREACHABLE();
146}
147
148// static
149int Bytecodes::GetOperandOffset(Bytecode bytecode, int i,
150                                OperandScale operand_scale) {
151  DCHECK_LT(i, Bytecodes::NumberOfOperands(bytecode));
152  // TODO(oth): restore this to a statically determined constant.
153  int offset = 1;
154  for (int operand_index = 0; operand_index < i; ++operand_index) {
155    OperandSize operand_size =
156        GetOperandSize(bytecode, operand_index, operand_scale);
157    offset += static_cast<int>(operand_size);
158  }
159  return offset;
160}
161
162// static
163Bytecode Bytecodes::GetJumpWithoutToBoolean(Bytecode bytecode) {
164  switch (bytecode) {
165    case Bytecode::kJumpIfToBooleanTrue:
166      return Bytecode::kJumpIfTrue;
167    case Bytecode::kJumpIfToBooleanFalse:
168      return Bytecode::kJumpIfFalse;
169    case Bytecode::kJumpIfToBooleanTrueConstant:
170      return Bytecode::kJumpIfTrueConstant;
171    case Bytecode::kJumpIfToBooleanFalseConstant:
172      return Bytecode::kJumpIfFalseConstant;
173    default:
174      break;
175  }
176  UNREACHABLE();
177}
178
179// static
180bool Bytecodes::IsDebugBreak(Bytecode bytecode) {
181  switch (bytecode) {
182#define CASE(Name, ...) case Bytecode::k##Name:
183    DEBUG_BREAK_BYTECODE_LIST(CASE);
184#undef CASE
185    return true;
186    default:
187      break;
188  }
189  return false;
190}
191
192// static
193bool Bytecodes::IsRegisterOperandType(OperandType operand_type) {
194  switch (operand_type) {
195#define CASE(Name, _)        \
196  case OperandType::k##Name: \
197    return true;
198    REGISTER_OPERAND_TYPE_LIST(CASE)
199#undef CASE
200#define CASE(Name, _)        \
201  case OperandType::k##Name: \
202    break;
203    NON_REGISTER_OPERAND_TYPE_LIST(CASE)
204#undef CASE
205  }
206  return false;
207}
208
209// static
210bool Bytecodes::IsRegisterListOperandType(OperandType operand_type) {
211  switch (operand_type) {
212    case OperandType::kRegList:
213    case OperandType::kRegOutList:
214      return true;
215    default:
216      return false;
217  }
218}
219
220bool Bytecodes::MakesCallAlongCriticalPath(Bytecode bytecode) {
221  if (IsCallOrConstruct(bytecode) || IsCallRuntime(bytecode)) return true;
222  switch (bytecode) {
223    case Bytecode::kCreateWithContext:
224    case Bytecode::kCreateBlockContext:
225    case Bytecode::kCreateCatchContext:
226    case Bytecode::kCreateRegExpLiteral:
227    case Bytecode::kGetIterator:
228      return true;
229    default:
230      return false;
231  }
232}
233
234// static
235bool Bytecodes::IsRegisterInputOperandType(OperandType operand_type) {
236  switch (operand_type) {
237#define CASE(Name, _)        \
238  case OperandType::k##Name: \
239    return true;
240    REGISTER_INPUT_OPERAND_TYPE_LIST(CASE)
241#undef CASE
242#define CASE(Name, _)        \
243  case OperandType::k##Name: \
244    break;
245    NON_REGISTER_OPERAND_TYPE_LIST(CASE)
246    REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE)
247#undef CASE
248  }
249  return false;
250}
251
252// static
253bool Bytecodes::IsRegisterOutputOperandType(OperandType operand_type) {
254  switch (operand_type) {
255#define CASE(Name, _)        \
256  case OperandType::k##Name: \
257    return true;
258    REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE)
259#undef CASE
260#define CASE(Name, _)        \
261  case OperandType::k##Name: \
262    break;
263    NON_REGISTER_OPERAND_TYPE_LIST(CASE)
264    REGISTER_INPUT_OPERAND_TYPE_LIST(CASE)
265#undef CASE
266  }
267  return false;
268}
269
270// static
271bool Bytecodes::IsStarLookahead(Bytecode bytecode, OperandScale operand_scale) {
272  if (operand_scale == OperandScale::kSingle) {
273    switch (bytecode) {
274      // Short-star lookahead is required for correctness on kDebugBreak0. The
275      // handler for all short-star codes re-reads the opcode from the bytecode
276      // array and would not work correctly if it instead read kDebugBreak0.
277      case Bytecode::kDebugBreak0:
278
279      case Bytecode::kLdaZero:
280      case Bytecode::kLdaSmi:
281      case Bytecode::kLdaNull:
282      case Bytecode::kLdaTheHole:
283      case Bytecode::kLdaConstant:
284      case Bytecode::kLdaUndefined:
285      case Bytecode::kLdaGlobal:
286      case Bytecode::kGetNamedProperty:
287      case Bytecode::kGetKeyedProperty:
288      case Bytecode::kLdaContextSlot:
289      case Bytecode::kLdaImmutableContextSlot:
290      case Bytecode::kLdaCurrentContextSlot:
291      case Bytecode::kLdaImmutableCurrentContextSlot:
292      case Bytecode::kAdd:
293      case Bytecode::kSub:
294      case Bytecode::kMul:
295      case Bytecode::kAddSmi:
296      case Bytecode::kSubSmi:
297      case Bytecode::kInc:
298      case Bytecode::kDec:
299      case Bytecode::kTypeOf:
300      case Bytecode::kCallAnyReceiver:
301      case Bytecode::kCallProperty:
302      case Bytecode::kCallProperty0:
303      case Bytecode::kCallProperty1:
304      case Bytecode::kCallProperty2:
305      case Bytecode::kCallUndefinedReceiver:
306      case Bytecode::kCallUndefinedReceiver0:
307      case Bytecode::kCallUndefinedReceiver1:
308      case Bytecode::kCallUndefinedReceiver2:
309      case Bytecode::kConstruct:
310      case Bytecode::kConstructWithSpread:
311      case Bytecode::kCreateObjectLiteral:
312      case Bytecode::kCreateArrayLiteral:
313      case Bytecode::kThrowReferenceErrorIfHole:
314      case Bytecode::kGetTemplateObject:
315        return true;
316      default:
317        return false;
318    }
319  }
320  return false;
321}
322
323// static
324bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) {
325  for (int i = 0; i < NumberOfOperands(bytecode); i++) {
326    if (OperandIsScalable(bytecode, i)) return true;
327  }
328  return false;
329}
330
331// static
332bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) {
333  switch (operand_type) {
334#define CASE(Name, _)        \
335  case OperandType::k##Name: \
336    return OperandTraits<OperandType::k##Name>::TypeInfoTraits::kIsUnsigned;
337    OPERAND_TYPE_LIST(CASE)
338#undef CASE
339  }
340  UNREACHABLE();
341}
342
343// static
344bool Bytecodes::BytecodeHasHandler(Bytecode bytecode,
345                                   OperandScale operand_scale) {
346  return (operand_scale == OperandScale::kSingle &&
347          (!IsShortStar(bytecode) || bytecode == Bytecode::kStar0)) ||
348         Bytecodes::IsBytecodeWithScalableOperands(bytecode);
349}
350
351std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) {
352  return os << Bytecodes::ToString(bytecode);
353}
354
355}  // namespace interpreter
356}  // namespace internal
357}  // namespace v8
358