source: webkit/trunk/Source/JavaScriptCore/testRegExp.cpp@ 174455

Last change on this file since 174455 was 174455, checked in by Brent Fulgham, 11 years ago

[Win] Resolve some static analysis warnings in JavaScriptCore
https://bugs.webkit.org/show_bug.cgi?id=137508

Reviewed by Geoffrey Garen.

  • API/tests/testapi.c:

(assertEqualsAsCharactersPtr): MSVC insists on using %Iu as its format specifier
for size_t. Make the format string conditional on Windows.

  • bytecode/Watchpoint.h:

(JSC::InlineWatchpointSet::encodeState): Silence warning about left-shifting 'state'
as a 32-bit value before OR-ing it with a 64-bit value.

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode): Silence warning about operator prescedence

causing the
operation to take place before the >= test.
  • dfg/DFGInPlaceAbstractState.cpp:
(JSC::DFG::InPlaceAbstractState::endBasicBlock): Ditto (
before !=)
  • testRegExp.cpp:

(testOneRegExp): Ditto %Iu format specifier.

  • yarr/YarrInterpreter.cpp:

(JSC::Yarr::Interpreter::allocParenthesesDisjunctionContext): Silence warning about
using a 32-bit value as part of a 64-bit calculation.

  • Property svn:eol-style set to native
File size: 14.6 KB
Line 
1/*
2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20
21#include "config.h"
22#include "RegExp.h"
23
24#include <wtf/CurrentTime.h>
25#include "InitializeThreading.h"
26#include "JSCInlines.h"
27#include "JSGlobalObject.h"
28#include <errno.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <wtf/text/StringBuilder.h>
33
34#if !OS(WINDOWS)
35#include <unistd.h>
36#endif
37
38#if HAVE(SYS_TIME_H)
39#include <sys/time.h>
40#endif
41
42#if COMPILER(MSVC)
43#include <crtdbg.h>
44#include <mmsystem.h>
45#include <windows.h>
46#endif
47
48namespace JSC {
49WTF_IMPORT extern const struct HashTable globalObjectTable;
50}
51
52const int MaxLineLength = 100 * 1024;
53
54using namespace JSC;
55using namespace WTF;
56
57struct CommandLine {
58 CommandLine()
59 : interactive(false)
60 , verbose(false)
61 {
62 }
63
64 bool interactive;
65 bool verbose;
66 Vector<String> arguments;
67 Vector<String> files;
68};
69
70class StopWatch {
71public:
72 void start();
73 void stop();
74 long getElapsedMS(); // call stop() first
75
76private:
77 double m_startTime;
78 double m_stopTime;
79};
80
81void StopWatch::start()
82{
83 m_startTime = monotonicallyIncreasingTime();
84}
85
86void StopWatch::stop()
87{
88 m_stopTime = monotonicallyIncreasingTime();
89}
90
91long StopWatch::getElapsedMS()
92{
93 return static_cast<long>((m_stopTime - m_startTime) * 1000);
94}
95
96struct RegExpTest {
97 RegExpTest()
98 : offset(0)
99 , result(0)
100 {
101 }
102
103 String subject;
104 int offset;
105 int result;
106 Vector<int, 32> expectVector;
107};
108
109class GlobalObject : public JSGlobalObject {
110private:
111 GlobalObject(VM&, Structure*, const Vector<String>& arguments);
112
113public:
114 typedef JSGlobalObject Base;
115
116 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
117 {
118 GlobalObject* globalObject = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure, arguments);
119 vm.heap.addFinalizer(globalObject, destroy);
120 return globalObject;
121 }
122
123 DECLARE_INFO;
124
125 static const bool needsDestructor = false;
126
127 static Structure* createStructure(VM& vm, JSValue prototype)
128 {
129 return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
130 }
131
132protected:
133 void finishCreation(VM& vm, const Vector<String>& arguments)
134 {
135 Base::finishCreation(vm);
136 UNUSED_PARAM(arguments);
137 }
138};
139
140const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, &globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
141
142GlobalObject::GlobalObject(VM& vm, Structure* structure, const Vector<String>& arguments)
143 : JSGlobalObject(vm, structure)
144{
145 finishCreation(vm, arguments);
146}
147
148// Use SEH for Release builds only to get rid of the crash report dialog
149// (luckily the same tests fail in Release and Debug builds so far). Need to
150// be in a separate main function because the realMain function requires object
151// unwinding.
152
153#if COMPILER(MSVC) && !defined(_DEBUG)
154#define TRY __try {
155#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
156#else
157#define TRY
158#define EXCEPT(x)
159#endif
160
161int realMain(int argc, char** argv);
162
163int main(int argc, char** argv)
164{
165#if OS(WINDOWS)
166 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
167 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
168 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
169 ::SetErrorMode(0);
170
171#if defined(_DEBUG)
172 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
173 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
174 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
175 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
176 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
177 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
178#endif
179
180 timeBeginPeriod(1);
181#endif
182
183 // Initialize JSC before getting VM.
184 JSC::initializeThreading();
185
186 // We can't use destructors in the following code because it uses Windows
187 // Structured Exception Handling
188 int res = 0;
189 TRY
190 res = realMain(argc, argv);
191 EXCEPT(res = 3)
192 return res;
193}
194
195static bool testOneRegExp(VM& vm, RegExp* regexp, RegExpTest* regExpTest, bool verbose, unsigned int lineNumber)
196{
197 bool result = true;
198 Vector<int, 32> outVector;
199 outVector.resize(regExpTest->expectVector.size());
200 int matchResult = regexp->match(vm, regExpTest->subject, regExpTest->offset, outVector);
201
202 if (matchResult != regExpTest->result) {
203 result = false;
204 if (verbose)
205 printf("Line %d: results mismatch - expected %d got %d\n", lineNumber, regExpTest->result, matchResult);
206 } else if (matchResult != -1) {
207 if (outVector.size() != regExpTest->expectVector.size()) {
208 result = false;
209 if (verbose) {
210#if OS(WINDOWS)
211 printf("Line %d: output vector size mismatch - expected %Iu got %Iu\n", lineNumber, regExpTest->expectVector.size(), outVector.size());
212#else
213 printf("Line %d: output vector size mismatch - expected %zu got %zu\n", lineNumber, regExpTest->expectVector.size(), outVector.size());
214#endif
215 }
216 } else if (outVector.size() % 2) {
217 result = false;
218 if (verbose) {
219#if OS(WINDOWS)
220 printf("Line %d: output vector size is odd (%Iu), should be even\n", lineNumber, outVector.size());
221#else
222 printf("Line %d: output vector size is odd (%zu), should be even\n", lineNumber, outVector.size());
223#endif
224 }
225 } else {
226 // Check in pairs since the first value of the pair could be -1 in which case the second doesn't matter.
227 size_t pairCount = outVector.size() / 2;
228 for (size_t i = 0; i < pairCount; ++i) {
229 size_t startIndex = i*2;
230 if (outVector[startIndex] != regExpTest->expectVector[startIndex]) {
231 result = false;
232 if (verbose) {
233#if OS(WINDOWS)
234 printf("Line %d: output vector mismatch at index %Iu - expected %d got %d\n", lineNumber, startIndex, regExpTest->expectVector[startIndex], outVector[startIndex]);
235#else
236 printf("Line %d: output vector mismatch at index %zu - expected %d got %d\n", lineNumber, startIndex, regExpTest->expectVector[startIndex], outVector[startIndex]);
237#endif
238 }
239 }
240 if ((i > 0) && (regExpTest->expectVector[startIndex] != -1) && (outVector[startIndex+1] != regExpTest->expectVector[startIndex+1])) {
241 result = false;
242 if (verbose) {
243#if OS(WINDOWS)
244 printf("Line %d: output vector mismatch at index %Iu - expected %d got %d\n", lineNumber, startIndex + 1, regExpTest->expectVector[startIndex + 1], outVector[startIndex + 1]);
245#else
246 printf("Line %d: output vector mismatch at index %zu - expected %d got %d\n", lineNumber, startIndex + 1, regExpTest->expectVector[startIndex + 1], outVector[startIndex + 1]);
247#endif
248 }
249 }
250 }
251 }
252 }
253
254 return result;
255}
256
257static int scanString(char* buffer, int bufferLength, StringBuilder& builder, char termChar)
258{
259 bool escape = false;
260
261 for (int i = 0; i < bufferLength; ++i) {
262 UChar c = buffer[i];
263
264 if (escape) {
265 switch (c) {
266 case '0':
267 c = '\0';
268 break;
269 case 'a':
270 c = '\a';
271 break;
272 case 'b':
273 c = '\b';
274 break;
275 case 'f':
276 c = '\f';
277 break;
278 case 'n':
279 c = '\n';
280 break;
281 case 'r':
282 c = '\r';
283 break;
284 case 't':
285 c = '\t';
286 break;
287 case 'v':
288 c = '\v';
289 break;
290 case '\\':
291 c = '\\';
292 break;
293 case '?':
294 c = '\?';
295 break;
296 case 'u':
297 if ((i + 4) >= bufferLength)
298 return -1;
299 unsigned int charValue;
300 if (sscanf(buffer+i+1, "%04x", &charValue) != 1)
301 return -1;
302 c = static_cast<UChar>(charValue);
303 i += 4;
304 break;
305 }
306
307 builder.append(c);
308 escape = false;
309 } else {
310 if (c == termChar)
311 return i;
312
313 if (c == '\\')
314 escape = true;
315 else
316 builder.append(c);
317 }
318 }
319
320 return -1;
321}
322
323static RegExp* parseRegExpLine(VM& vm, char* line, int lineLength)
324{
325 StringBuilder pattern;
326
327 if (line[0] != '/')
328 return 0;
329
330 int i = scanString(line + 1, lineLength - 1, pattern, '/') + 1;
331
332 if ((i >= lineLength) || (line[i] != '/'))
333 return 0;
334
335 ++i;
336
337 return RegExp::create(vm, pattern.toString(), regExpFlags(line + i));
338}
339
340static RegExpTest* parseTestLine(char* line, int lineLength)
341{
342 StringBuilder subjectString;
343
344 if ((line[0] != ' ') || (line[1] != '"'))
345 return 0;
346
347 int i = scanString(line + 2, lineLength - 2, subjectString, '"') + 2;
348
349 if ((i >= (lineLength - 2)) || (line[i] != '"') || (line[i+1] != ',') || (line[i+2] != ' '))
350 return 0;
351
352 i += 3;
353
354 int offset;
355
356 if (sscanf(line + i, "%d, ", &offset) != 1)
357 return 0;
358
359 while (line[i] && line[i] != ' ')
360 ++i;
361
362 ++i;
363
364 int matchResult;
365
366 if (sscanf(line + i, "%d, ", &matchResult) != 1)
367 return 0;
368
369 while (line[i] && line[i] != ' ')
370 ++i;
371
372 ++i;
373
374 if (line[i++] != '(')
375 return 0;
376
377 int start, end;
378
379 RegExpTest* result = new RegExpTest();
380
381 result->subject = subjectString.toString();
382 result->offset = offset;
383 result->result = matchResult;
384
385 while (line[i] && line[i] != ')') {
386 if (sscanf(line + i, "%d, %d", &start, &end) != 2) {
387 delete result;
388 return 0;
389 }
390
391 result->expectVector.append(start);
392 result->expectVector.append(end);
393
394 while (line[i] && (line[i] != ',') && (line[i] != ')'))
395 i++;
396 i++;
397 while (line[i] && (line[i] != ',') && (line[i] != ')'))
398 i++;
399
400 if (line[i] == ')')
401 break;
402 if (!line[i] || (line[i] != ',')) {
403 delete result;
404 return 0;
405 }
406 i++;
407 }
408
409 return result;
410}
411
412static bool runFromFiles(GlobalObject* globalObject, const Vector<String>& files, bool verbose)
413{
414 String script;
415 String fileName;
416 Vector<char> scriptBuffer;
417 unsigned tests = 0;
418 unsigned failures = 0;
419 char* lineBuffer = new char[MaxLineLength + 1];
420
421 VM& vm = globalObject->vm();
422
423 bool success = true;
424 for (size_t i = 0; i < files.size(); i++) {
425 FILE* testCasesFile = fopen(files[i].utf8().data(), "rb");
426
427 if (!testCasesFile) {
428 printf("Unable to open test data file \"%s\"\n", files[i].utf8().data());
429 continue;
430 }
431
432 RegExp* regexp = 0;
433 size_t lineLength = 0;
434 char* linePtr = 0;
435 unsigned int lineNumber = 0;
436
437 while ((linePtr = fgets(&lineBuffer[0], MaxLineLength, testCasesFile))) {
438 lineLength = strlen(linePtr);
439 if (linePtr[lineLength - 1] == '\n') {
440 linePtr[lineLength - 1] = '\0';
441 --lineLength;
442 }
443 ++lineNumber;
444
445 if (linePtr[0] == '#')
446 continue;
447
448 if (linePtr[0] == '/') {
449 regexp = parseRegExpLine(vm, linePtr, lineLength);
450 } else if (linePtr[0] == ' ') {
451 RegExpTest* regExpTest = parseTestLine(linePtr, lineLength);
452
453 if (regexp && regExpTest) {
454 ++tests;
455 if (!testOneRegExp(vm, regexp, regExpTest, verbose, lineNumber)) {
456 failures++;
457 printf("Failure on line %u\n", lineNumber);
458 }
459 }
460
461 if (regExpTest)
462 delete regExpTest;
463 }
464 }
465
466 fclose(testCasesFile);
467 }
468
469 if (failures)
470 printf("%u tests run, %u failures\n", tests, failures);
471 else
472 printf("%u tests passed\n", tests);
473
474 delete[] lineBuffer;
475
476 vm.dumpSampleData(globalObject->globalExec());
477#if ENABLE(REGEXP_TRACING)
478 vm.dumpRegExpTrace();
479#endif
480 return success;
481}
482
483#define RUNNING_FROM_XCODE 0
484
485static NO_RETURN void printUsageStatement(bool help = false)
486{
487 fprintf(stderr, "Usage: regexp_test [options] file\n");
488 fprintf(stderr, " -h|--help Prints this help message\n");
489 fprintf(stderr, " -v|--verbose Verbose output\n");
490
491 exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
492}
493
494static void parseArguments(int argc, char** argv, CommandLine& options)
495{
496 int i = 1;
497 for (; i < argc; ++i) {
498 const char* arg = argv[i];
499 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
500 printUsageStatement(true);
501 if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose"))
502 options.verbose = true;
503 else
504 options.files.append(argv[i]);
505 }
506
507 for (; i < argc; ++i)
508 options.arguments.append(argv[i]);
509}
510
511int realMain(int argc, char** argv)
512{
513 VM* vm = VM::create(LargeHeap).leakRef();
514 JSLockHolder locker(vm);
515
516 CommandLine options;
517 parseArguments(argc, argv, options);
518
519 GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.arguments);
520 bool success = runFromFiles(globalObject, options.files, options.verbose);
521
522 return success ? 0 : 3;
523}
524
525#if OS(WINDOWS)
526extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[])
527{
528 return main(argc, const_cast<char**>(argv));
529}
530#endif
Note: See TracBrowser for help on using the repository browser.