OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <cstring> | 5 #include <cstring> |
6 #include <fstream> | 6 #include <fstream> |
7 | 7 |
8 #include "test/cctest/interpreter/bytecode-expectations-printer.h" | 8 #include "test/cctest/interpreter/bytecode-expectations-printer.h" |
9 | 9 |
10 #include "include/libplatform/libplatform.h" | 10 #include "include/libplatform/libplatform.h" |
(...skipping 10 matching lines...) Expand all Loading... | |
21 | 21 |
22 class ProgramOptions { | 22 class ProgramOptions { |
23 public: | 23 public: |
24 static ProgramOptions FromCommandLine(int argc, char** argv); | 24 static ProgramOptions FromCommandLine(int argc, char** argv); |
25 | 25 |
26 ProgramOptions() | 26 ProgramOptions() |
27 : parsing_failed_(false), | 27 : parsing_failed_(false), |
28 print_help_(false), | 28 print_help_(false), |
29 read_raw_js_snippet_(false), | 29 read_raw_js_snippet_(false), |
30 read_from_stdin_(false), | 30 read_from_stdin_(false), |
31 rebaseline_(false), | |
32 wrap_(true), | |
33 execute_(true), | |
31 const_pool_type_( | 34 const_pool_type_( |
32 BytecodeExpectationsPrinter::ConstantPoolType::kMixed) {} | 35 BytecodeExpectationsPrinter::ConstantPoolType::kMixed) {} |
33 | 36 |
34 bool Validate() const; | 37 bool Validate() const; |
35 | 38 |
36 bool parsing_failed() const { return parsing_failed_; } | 39 bool parsing_failed() const { return parsing_failed_; } |
37 bool print_help() const { return print_help_; } | 40 bool print_help() const { return print_help_; } |
38 bool read_raw_js_snippet() const { return read_raw_js_snippet_; } | 41 bool read_raw_js_snippet() const { return read_raw_js_snippet_; } |
39 bool read_from_stdin() const { return read_from_stdin_; } | 42 bool read_from_stdin() const { return read_from_stdin_; } |
40 std::string filename() const { return filename_; } | 43 bool rebaseline() const { return rebaseline_; } |
44 bool wrap() const { return wrap_; } | |
45 bool execute() const { return execute_; } | |
41 BytecodeExpectationsPrinter::ConstantPoolType const_pool_type() const { | 46 BytecodeExpectationsPrinter::ConstantPoolType const_pool_type() const { |
42 return const_pool_type_; | 47 return const_pool_type_; |
43 } | 48 } |
49 std::string input_filename() const { return input_filename_; } | |
50 std::string output_filename() const { return output_file_name_; } | |
51 std::string top_function_name() const { return top_function_name_; } | |
44 | 52 |
45 private: | 53 private: |
46 bool parsing_failed_; | 54 bool parsing_failed_; |
47 bool print_help_; | 55 bool print_help_; |
48 bool read_raw_js_snippet_; | 56 bool read_raw_js_snippet_; |
49 bool read_from_stdin_; | 57 bool read_from_stdin_; |
58 bool rebaseline_; | |
59 bool wrap_; | |
60 bool execute_; | |
50 BytecodeExpectationsPrinter::ConstantPoolType const_pool_type_; | 61 BytecodeExpectationsPrinter::ConstantPoolType const_pool_type_; |
51 std::string filename_; | 62 std::string input_filename_; |
63 std::string output_file_name_; | |
64 std::string top_function_name_; | |
65 | |
66 friend void MaybeUpdateOptionsFromHeader(ProgramOptions*, std::istream&); | |
rmcilroy
2016/02/17 15:24:08
Don't make this a friend, just add setters for the
Stefano Sanfilippo
2016/02/17 16:40:50
Done.
| |
52 }; | 67 }; |
53 | 68 |
54 class ArrayBufferAllocator final : public v8::ArrayBuffer::Allocator { | 69 class ArrayBufferAllocator final : public v8::ArrayBuffer::Allocator { |
55 public: | 70 public: |
56 void* Allocate(size_t length) override { | 71 void* Allocate(size_t length) override { |
57 void* data = AllocateUninitialized(length); | 72 void* data = AllocateUninitialized(length); |
58 if (data != nullptr) memset(data, 0, length); | 73 if (data != nullptr) memset(data, 0, length); |
59 return data; | 74 return data; |
60 } | 75 } |
61 void* AllocateUninitialized(size_t length) override { return malloc(length); } | 76 void* AllocateUninitialized(size_t length) override { return malloc(length); } |
(...skipping 26 matching lines...) Expand all Loading... | |
88 } else if (strcmp(type_string, "mixed") == 0) { | 103 } else if (strcmp(type_string, "mixed") == 0) { |
89 return BytecodeExpectationsPrinter::ConstantPoolType::kMixed; | 104 return BytecodeExpectationsPrinter::ConstantPoolType::kMixed; |
90 } | 105 } |
91 return BytecodeExpectationsPrinter::ConstantPoolType::kUnknown; | 106 return BytecodeExpectationsPrinter::ConstantPoolType::kUnknown; |
92 } | 107 } |
93 | 108 |
94 // static | 109 // static |
95 ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) { | 110 ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) { |
96 ProgramOptions options; | 111 ProgramOptions options; |
97 | 112 |
98 if (argc <= 1) return options; | |
99 | |
100 for (int i = 1; i < argc; ++i) { | 113 for (int i = 1; i < argc; ++i) { |
101 if (strcmp(argv[i], "--help") == 0) { | 114 if (strcmp(argv[i], "--help") == 0) { |
102 options.print_help_ = true; | 115 options.print_help_ = true; |
103 } else if (strcmp(argv[i], "--raw-js") == 0) { | 116 } else if (strcmp(argv[i], "--raw-js") == 0) { |
104 options.read_raw_js_snippet_ = true; | 117 options.read_raw_js_snippet_ = true; |
105 } else if (strncmp(argv[i], "--pool-type=", 12) == 0) { | 118 } else if (strncmp(argv[i], "--pool-type=", 12) == 0) { |
106 options.const_pool_type_ = ParseConstantPoolType(argv[i] + 12); | 119 options.const_pool_type_ = ParseConstantPoolType(argv[i] + 12); |
107 } else if (strcmp(argv[i], "--stdin") == 0) { | 120 } else if (strcmp(argv[i], "--stdin") == 0) { |
108 options.read_from_stdin_ = true; | 121 options.read_from_stdin_ = true; |
122 } else if (strcmp(argv[i], "--rebaseline") == 0) { | |
123 options.rebaseline_ = true; | |
124 } else if (strcmp(argv[i], "--no-wrap") == 0) { | |
125 options.wrap_ = false; | |
126 } else if (strcmp(argv[i], "--no-execute") == 0) { | |
127 options.execute_ = false; | |
128 } else if (strncmp(argv[i], "--output=", 9) == 0) { | |
129 options.output_file_name_ = argv[i] + 9; | |
130 } else if (strncmp(argv[i], "--wrapper-name=", 15) == 0) { | |
131 options.top_function_name_ = argv[i] + 15; | |
109 } else if (strncmp(argv[i], "--", 2) != 0) { // It doesn't start with -- | 132 } else if (strncmp(argv[i], "--", 2) != 0) { // It doesn't start with -- |
110 if (!options.filename_.empty()) { | 133 if (!options.input_filename_.empty()) { |
111 std::cerr << "ERROR: More than one input file specified\n"; | 134 std::cerr << "ERROR: More than one input file specified\n"; |
112 options.parsing_failed_ = true; | 135 options.parsing_failed_ = true; |
113 break; | 136 break; |
114 } | 137 } |
115 options.filename_ = argv[i]; | 138 options.input_filename_ = argv[i]; |
116 } else { | 139 } else { |
117 std::cerr << "ERROR: Unknonwn option " << argv[i] << "\n"; | 140 std::cerr << "ERROR: Unknonwn option " << argv[i] << "\n"; |
118 options.parsing_failed_ = true; | 141 options.parsing_failed_ = true; |
119 break; | 142 break; |
120 } | 143 } |
121 } | 144 } |
122 | 145 |
123 return options; | 146 return options; |
124 } | 147 } |
125 | 148 |
149 bool ParseBoolean(const char* string) { | |
150 if (strcmp(string, "yes") == 0) { | |
151 return true; | |
152 } else if (strcmp(string, "no") == 0) { | |
153 return false; | |
154 } else { | |
155 UNREACHABLE(); | |
156 return false; | |
157 } | |
158 } | |
159 | |
160 void MaybeUpdateOptionsFromHeader(ProgramOptions* options, | |
161 std::istream& stream) { // NOLINT | |
162 std::string line; | |
163 | |
164 if (options->read_raw_js_snippet()) return; | |
165 | |
166 // Skip to the beginning of the options header | |
167 while (std::getline(stream, line)) { | |
168 if (line == "---") break; | |
169 } | |
170 | |
171 while (std::getline(stream, line)) { | |
172 if (line.compare(0, 11, "pool type: ") == 0) { | |
173 options->const_pool_type_ = ParseConstantPoolType(line.c_str() + 11); | |
174 } else if (line.compare(0, 9, "execute: ") == 0) { | |
175 options->execute_ = ParseBoolean(line.c_str() + 9); | |
176 } else if (line.compare(0, 6, "wrap: ") == 0) { | |
177 options->wrap_ = ParseBoolean(line.c_str() + 6); | |
178 } else if (line.compare(0, 14, "wrapper name: ") == 0) { | |
179 options->top_function_name_ = line.c_str() + 14; | |
180 } else if (line == "---") { | |
181 break; | |
182 } else if (line.empty()) { | |
183 continue; | |
184 } else { | |
185 UNREACHABLE(); | |
186 return; | |
187 } | |
188 } | |
189 } | |
190 | |
126 bool ProgramOptions::Validate() const { | 191 bool ProgramOptions::Validate() const { |
127 if (parsing_failed_) return false; | 192 if (parsing_failed_) return false; |
128 if (print_help_) return true; | 193 if (print_help_) return true; |
129 | 194 |
130 if (const_pool_type_ == | 195 if (const_pool_type_ == |
131 BytecodeExpectationsPrinter::ConstantPoolType::kUnknown) { | 196 BytecodeExpectationsPrinter::ConstantPoolType::kUnknown) { |
132 std::cerr << "ERROR: Unknown constant pool type.\n"; | 197 std::cerr << "ERROR: Unknown constant pool type.\n"; |
133 return false; | 198 return false; |
134 } | 199 } |
135 | 200 |
136 if (!read_from_stdin_ && filename_.empty()) { | 201 if (!read_from_stdin_ && input_filename_.empty()) { |
137 std::cerr << "ERROR: No input file specified.\n"; | 202 std::cerr << "ERROR: No input file specified.\n"; |
138 return false; | 203 return false; |
139 } | 204 } |
140 | 205 |
141 if (read_from_stdin_ && !filename_.empty()) { | 206 if (read_from_stdin_ && !input_filename_.empty()) { |
142 std::cerr << "ERROR: Reading from stdin, but input files supplied.\n"; | 207 std::cerr << "ERROR: Reading from stdin, but input files supplied.\n"; |
143 return false; | 208 return false; |
144 } | 209 } |
145 | 210 |
211 if (!wrap_ && !top_function_name_.empty()) { | |
212 std::cerr << "ERROR: Not wrapping, but wrapper name specified.\n"; | |
213 return false; | |
214 } | |
215 | |
216 if (rebaseline_ && read_raw_js_snippet_) { | |
217 std::cerr << "ERROR: Cannot use --rebaseline on a raw JS snippet.\n"; | |
218 return false; | |
219 } | |
220 | |
146 return true; | 221 return true; |
147 } | 222 } |
148 | 223 |
149 V8InitializationScope::V8InitializationScope(const char* exec_path) | 224 V8InitializationScope::V8InitializationScope(const char* exec_path) |
150 : platform_(v8::platform::CreateDefaultPlatform()) { | 225 : platform_(v8::platform::CreateDefaultPlatform()) { |
151 i::FLAG_ignition = true; | 226 i::FLAG_ignition = true; |
152 i::FLAG_always_opt = false; | 227 i::FLAG_always_opt = false; |
153 i::FLAG_allow_natives_syntax = true; | 228 i::FLAG_allow_natives_syntax = true; |
154 | 229 |
155 v8::V8::InitializeICU(); | 230 v8::V8::InitializeICU(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
187 } | 262 } |
188 if (!found_begin_snippet) continue; | 263 if (!found_begin_snippet) continue; |
189 if (line == "\"") return true; | 264 if (line == "\"") return true; |
190 CHECK_GE(line.size(), 2u); // We should have the indent | 265 CHECK_GE(line.size(), 2u); // We should have the indent |
191 string_out->append(line.begin() + 2, line.end()); | 266 string_out->append(line.begin() + 2, line.end()); |
192 *string_out += '\n'; | 267 *string_out += '\n'; |
193 } | 268 } |
194 return false; | 269 return false; |
195 } | 270 } |
196 | 271 |
197 void ExtractSnippetsFromStream(std::vector<std::string>* snippet_list, | 272 std::string UnescapeString(const std::string& escaped_string) { |
198 std::istream& body_stream, // NOLINT | 273 std::string unescaped_string; |
199 bool read_raw_js_snippet) { | 274 bool previous_was_backslash = false; |
275 for (char c : escaped_string) { | |
276 if (previous_was_backslash) { | |
277 // If it was not an escape sequence, emit the previous backslash | |
278 if (c != '\\' && c != '"') unescaped_string += '\\'; | |
279 unescaped_string += c; | |
280 previous_was_backslash = false; | |
281 } else { | |
282 if (c == '\\') { | |
283 previous_was_backslash = true; | |
284 // Defer emission to the point where we can check if it was an escape. | |
285 } else { | |
286 unescaped_string += c; | |
287 } | |
288 } | |
289 } | |
290 return unescaped_string; | |
291 } | |
292 | |
293 void ExtractSnippets(std::vector<std::string>* snippet_list, | |
294 std::istream& body_stream, // NOLINT | |
295 bool read_raw_js_snippet) { | |
200 if (read_raw_js_snippet) { | 296 if (read_raw_js_snippet) { |
201 snippet_list->push_back(ReadRawJSSnippet(body_stream)); | 297 snippet_list->push_back(ReadRawJSSnippet(body_stream)); |
202 } else { | 298 } else { |
203 std::string snippet; | 299 std::string snippet; |
204 while (ReadNextSnippet(body_stream, &snippet)) { | 300 while (ReadNextSnippet(body_stream, &snippet)) { |
205 snippet_list->push_back(snippet); | 301 snippet_list->push_back(UnescapeString(snippet)); |
206 } | 302 } |
207 } | 303 } |
208 } | 304 } |
209 | 305 |
210 bool ExtractSnippets(std::vector<std::string>* snippet_list, | 306 void GenerateExpectationsFile(std::ostream& stream, // NOLINT |
211 const ProgramOptions& options) { | 307 const std::vector<std::string>& snippet_list, |
212 if (options.read_from_stdin()) { | 308 const ProgramOptions& options, |
213 ExtractSnippetsFromStream(snippet_list, std::cin, | 309 const char* exec_path) { |
214 options.read_raw_js_snippet()); | |
215 } else { | |
216 std::ifstream body_file(options.filename().c_str()); | |
217 if (!body_file.is_open()) { | |
218 std::cerr << "ERROR: Could not open '" << options.filename() << "'.\n"; | |
219 return false; | |
220 } | |
221 ExtractSnippetsFromStream(snippet_list, body_file, | |
222 options.read_raw_js_snippet()); | |
223 } | |
224 return true; | |
225 } | |
226 | |
227 void GenerateExpectationsFile( | |
228 std::ostream& stream, // NOLINT | |
229 const std::vector<std::string>& snippet_list, | |
230 BytecodeExpectationsPrinter::ConstantPoolType const_pool_type, | |
231 const char* exec_path) { | |
232 V8InitializationScope platform(exec_path); | 310 V8InitializationScope platform(exec_path); |
233 { | 311 { |
234 v8::Isolate::Scope isolate_scope(platform.isolate()); | 312 v8::Isolate::Scope isolate_scope(platform.isolate()); |
235 v8::HandleScope handle_scope(platform.isolate()); | 313 v8::HandleScope handle_scope(platform.isolate()); |
236 v8::Local<v8::Context> context = v8::Context::New(platform.isolate()); | 314 v8::Local<v8::Context> context = v8::Context::New(platform.isolate()); |
237 v8::Context::Scope context_scope(context); | 315 v8::Context::Scope context_scope(context); |
238 | 316 |
239 stream << "#\n# Autogenerated by generate-bytecode-expectations\n#\n\n"; | 317 BytecodeExpectationsPrinter printer(platform.isolate(), |
318 options.const_pool_type()); | |
319 printer.set_wrap(options.wrap()); | |
320 printer.set_execute(options.execute()); | |
321 if (!options.top_function_name().empty()) { | |
322 printer.set_top_function_name(options.top_function_name()); | |
323 } | |
240 | 324 |
241 BytecodeExpectationsPrinter printer(platform.isolate(), const_pool_type); | 325 printer.PrintExpectationsArray(stream, snippet_list); |
242 for (const std::string& snippet : snippet_list) { | |
243 printer.PrintExpectation(stream, snippet); | |
244 } | |
245 } | 326 } |
246 } | 327 } |
247 | 328 |
248 void PrintUsage(const char* exec_path) { | 329 void PrintUsage(const char* exec_path) { |
249 std::cerr | 330 std::cerr |
250 << "\nUsage: " << exec_path | 331 << "\nUsage: " << exec_path |
251 << " [OPTIONS]... [INPUT FILE]\n\n" | 332 << " [OPTIONS]... [INPUT FILE]\n\n" |
252 "Options:\n" | 333 "Options:\n" |
253 " --help Print this help message.\n" | 334 " --help Print this help message.\n" |
254 " --raw-js Read raw JavaScript, instead of the output format.\n" | 335 " --raw-js Read raw JavaScript, instead of the output format.\n" |
255 " --stdin Read from standard input instead of file.\n" | 336 " --stdin Read from standard input instead of file.\n" |
337 " --rebaseline Rebaseline input snippet file.\n" | |
338 " --no-wrap Do not wrap the snippet in a function.\n" | |
339 " --no-execute Do not execute after compilation.\n" | |
340 " --wrapper-name=foo Specify the name of the wrapper function.\n" | |
341 " --output=file.name\n" | |
342 " Specify the output file. If not specified, output goes to " | |
343 "stdout.\n" | |
256 " --pool-type=(int|double|string|mixed)\n" | 344 " --pool-type=(int|double|string|mixed)\n" |
257 " specify the type of the entries in the constant pool " | 345 " Specify the type of the entries in the constant pool " |
258 "(default: mixed).\n" | 346 "(default: mixed).\n" |
259 "\n" | 347 "\n" |
348 "Flags --no-wrap, --no-execute, --wrapper-name and --pool-type will\n" | |
349 "be overridden by the options specified in the input file header.\n\n" | |
260 "Each raw JavaScript file is interpreted as a single snippet.\n\n" | 350 "Each raw JavaScript file is interpreted as a single snippet.\n\n" |
261 "This tool is intended as a help in writing tests.\n" | 351 "This tool is intended as a help in writing tests.\n" |
262 "Please, DO NOT blindly copy and paste the output " | 352 "Please, DO NOT blindly copy and paste the output " |
263 "into the test suite.\n"; | 353 "into the test suite.\n"; |
264 } | 354 } |
265 | 355 |
266 } // namespace | 356 } // namespace |
267 | 357 |
268 int main(int argc, char** argv) { | 358 int main(int argc, char** argv) { |
269 ProgramOptions options = ProgramOptions::FromCommandLine(argc, argv); | 359 ProgramOptions options = ProgramOptions::FromCommandLine(argc, argv); |
270 | 360 |
271 if (!options.Validate() || options.print_help()) { | 361 if (!options.Validate() || options.print_help()) { |
272 PrintUsage(argv[0]); | 362 PrintUsage(argv[0]); |
273 return options.print_help() ? 0 : 1; | 363 return options.print_help() ? 0 : 1; |
274 } | 364 } |
275 | 365 |
276 std::vector<std::string> snippet_list; | 366 std::ifstream body_file; |
277 if (!ExtractSnippets(&snippet_list, options)) { | 367 if (!options.read_from_stdin()) { |
278 return 2; | 368 body_file.open(options.input_filename().c_str()); |
369 if (!body_file.is_open()) { | |
370 std::cerr << "ERROR: Could not open '" << options.input_filename() | |
371 << "' for reading.\n"; | |
372 return 2; | |
373 } | |
279 } | 374 } |
280 | 375 |
281 GenerateExpectationsFile(std::cout, snippet_list, options.const_pool_type(), | 376 std::istream& body_stream = options.read_from_stdin() ? std::cin : body_file; |
rmcilroy
2016/02/17 15:24:08
Extract lines 366-376 into a function which return
Stefano Sanfilippo
2016/02/17 16:40:50
Done. I had to resort to a less elegant way of doi
rmcilroy
2016/02/17 17:06:36
Sorry, when I said go back to the way you were ori
Stefano Sanfilippo
2016/02/17 17:31:18
Done. Sorry for the misunderstanding :)
| |
282 argv[0]); | 377 MaybeUpdateOptionsFromHeader(&options, body_stream); |
rmcilroy
2016/02/17 15:24:08
I would do:
if (options->rebaseline) {
UpdateOp
Stefano Sanfilippo
2016/02/17 16:40:50
Done.
| |
378 CHECK(options.Validate()); | |
379 | |
380 std::vector<std::string> snippet_list; | |
381 ExtractSnippets(&snippet_list, body_file, options.read_raw_js_snippet()); | |
382 | |
383 bool write_to_stdout = | |
384 options.output_filename().empty() && !options.rebaseline(); | |
385 | |
386 std::ofstream output_file; | |
387 if (!write_to_stdout) { | |
388 output_file.open(options.rebaseline() ? options.input_filename().c_str() | |
389 : options.output_filename().c_str()); | |
390 if (!output_file.is_open()) { | |
391 std::cerr << "ERROR: Could not open '" << options.output_filename() | |
392 << "' for writing.\n"; | |
393 return 3; | |
394 } | |
395 } | |
rmcilroy
2016/02/17 15:24:08
Also pull out the ostream creation to a helper fun
Stefano Sanfilippo
2016/02/17 16:40:50
Done, see above.
| |
396 | |
397 std::ostream& output_stream = write_to_stdout ? std::cout : output_file; | |
398 GenerateExpectationsFile(output_stream, snippet_list, options, argv[0]); | |
283 } | 399 } |
OLD | NEW |