1// Copyright 2018 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 <fstream>
6#include <iostream>
7
8#include "src/interpreter/bytecodes.h"
9
10namespace v8 {
11namespace internal {
12namespace interpreter {
13
14const int kIllegalBytecodeHandler = -1;
15const int kIllegalBytecodeHandlerEncoding = 255;
16
17void WriteBytecode(std::ofstream& out, Bytecode bytecode,
18                   OperandScale operand_scale, int* count, int offset_table[],
19                   int table_index) {
20  DCHECK_NOT_NULL(count);
21  if (Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) {
22    std::string name = Bytecodes::ToString(bytecode, operand_scale, "");
23
24    // The handler for Star0 is used for all short star codes. Rename it to
25    // something more generic.
26    if (bytecode == Bytecode::kStar0) {
27      DCHECK_EQ(operand_scale, OperandScale::kSingle);
28      name = "ShortStar";
29    }
30
31    out << " \\\n  V(" << name << "Handler, interpreter::OperandScale::k"
32        << operand_scale << ", interpreter::Bytecode::k"
33        << Bytecodes::ToString(bytecode) << ")";
34    offset_table[table_index] = *count;
35    (*count)++;
36  } else {
37    offset_table[table_index] = kIllegalBytecodeHandler;
38  }
39}
40
41void WriteHeader(const char* header_filename) {
42  std::ofstream out(header_filename);
43
44  out << "// Automatically generated from interpreter/bytecodes.h\n"
45      << "// The following list macro is used to populate the builtins list\n"
46      << "// with the bytecode handlers\n\n"
47      << "#include <stdint.h>\n\n"
48      << "#ifndef V8_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST\n"
49      << "#define V8_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST\n\n"
50      << "namespace v8 {\n"
51      << "namespace internal {\n\n"
52      << "#define BUILTIN_LIST_BYTECODE_HANDLERS(V)";
53
54  constexpr int kTableSize =
55      BytecodeOperands::kOperandScaleCount * Bytecodes::kBytecodeCount;
56  int offset_table[kTableSize];
57  int count = 0;
58  int index = 0;
59
60#define ADD_BYTECODES(Name, ...)                                             \
61  WriteBytecode(out, Bytecode::k##Name, operand_scale, &count, offset_table, \
62                index++);
63  OperandScale operand_scale = OperandScale::kSingle;
64  BYTECODE_LIST(ADD_BYTECODES)
65  int single_count = count;
66  operand_scale = OperandScale::kDouble;
67  BYTECODE_LIST(ADD_BYTECODES)
68  int wide_count = count - single_count;
69  operand_scale = OperandScale::kQuadruple;
70  BYTECODE_LIST(ADD_BYTECODES)
71#undef ADD_BYTECODES
72  int extra_wide_count = count - wide_count - single_count;
73  CHECK_GT(single_count, wide_count);
74  CHECK_EQ(single_count,
75           Bytecodes::kBytecodeCount - Bytecodes::kShortStarCount + 1);
76  CHECK_EQ(wide_count, extra_wide_count);
77  out << "\n\nconstexpr int kNumberOfBytecodeHandlers = " << single_count
78      << ";\n"
79      << "constexpr int kNumberOfWideBytecodeHandlers = " << wide_count
80      << ";\n\n"
81      << "constexpr uint8_t kIllegalBytecodeHandlerEncoding = "
82      << kIllegalBytecodeHandlerEncoding << ";\n\n"
83      << "// Mapping from Bytecode to a dense form with all the illegal\n"
84      << "// wide Bytecodes removed. Used to index into the builtins table.\n"
85      << "constexpr uint8_t kWideBytecodeToBuiltinsMapping["
86      << Bytecodes::kBytecodeCount << "] = {    \n";
87
88  for (int i = Bytecodes::kBytecodeCount; i < 2 * Bytecodes::kBytecodeCount;
89       ++i) {
90    int offset = offset_table[i];
91    if (offset == kIllegalBytecodeHandler) {
92      offset = kIllegalBytecodeHandlerEncoding;
93    } else {
94      offset -= single_count;
95    }
96    out << offset << ", ";
97  }
98
99  out << "};\n\n"
100      << "}  // namespace internal\n"
101      << "}  // namespace v8\n"
102      << "#endif  // V8_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST\n";
103}
104
105}  // namespace interpreter
106}  // namespace internal
107}  // namespace v8
108
109int main(int argc, const char* argv[]) {
110  if (argc != 2) {
111    std::cerr << "Usage: " << argv[0] << " <output filename>\n";
112    std::exit(1);
113  }
114
115  v8::internal::interpreter::WriteHeader(argv[1]);
116
117  return 0;
118}
119