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 
10 namespace v8 {
11 namespace internal {
12 namespace interpreter {
13 
14 const int kIllegalBytecodeHandler = -1;
15 const int kIllegalBytecodeHandlerEncoding = 255;
16 
WriteBytecode(std::ofstream& out, Bytecode bytecode, OperandScale operand_scale, int* count, int offset_table[], int table_index)17 void 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 
WriteHeader(const char* header_filename)41 void 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 
main(int argc, const char* argv[])109 int 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