2 * Copyright (C) 2011, 2015 Apple Inc. All rights reserved.
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.
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.
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.
24 #include <wtf/CurrentTime.h>
25 #include "InitializeThreading.h"
26 #include "JSCInlines.h"
27 #include "JSGlobalObject.h"
32 #include <wtf/text/StringBuilder.h>
49 WTF_IMPORT
extern const struct HashTable globalObjectTable
;
52 const int MaxLineLength
= 100 * 1024;
66 Vector
<String
> arguments
;
74 long getElapsedMS(); // call stop() first
81 void StopWatch::start()
83 m_startTime
= monotonicallyIncreasingTime();
86 void StopWatch::stop()
88 m_stopTime
= monotonicallyIncreasingTime();
91 long StopWatch::getElapsedMS()
93 return static_cast<long>((m_stopTime
- m_startTime
) * 1000);
106 Vector
<int, 32> expectVector
;
109 class GlobalObject
: public JSGlobalObject
{
111 GlobalObject(VM
&, Structure
*, const Vector
<String
>& arguments
);
114 typedef JSGlobalObject Base
;
116 static GlobalObject
* create(VM
& vm
, Structure
* structure
, const Vector
<String
>& arguments
)
118 GlobalObject
* globalObject
= new (NotNull
, allocateCell
<GlobalObject
>(vm
.heap
)) GlobalObject(vm
, structure
, arguments
);
119 vm
.heap
.addFinalizer(globalObject
, destroy
);
125 static const bool needsDestructor
= false;
127 static Structure
* createStructure(VM
& vm
, JSValue prototype
)
129 return Structure::create(vm
, 0, prototype
, TypeInfo(GlobalObjectType
, StructureFlags
), info());
133 void finishCreation(VM
& vm
, const Vector
<String
>& arguments
)
135 Base::finishCreation(vm
);
136 UNUSED_PARAM(arguments
);
140 const ClassInfo
GlobalObject::s_info
= { "global", &JSGlobalObject::s_info
, &globalObjectTable
, CREATE_METHOD_TABLE(GlobalObject
) };
142 GlobalObject::GlobalObject(VM
& vm
, Structure
* structure
, const Vector
<String
>& arguments
)
143 : JSGlobalObject(vm
, structure
)
145 finishCreation(vm
, arguments
);
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
153 #if COMPILER(MSVC) && !defined(_DEBUG)
155 #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
161 int realMain(int argc
, char** argv
);
163 int main(int argc
, char** argv
)
166 #if defined(_M_X64) || defined(__x86_64__)
167 // The VS2013 runtime has a bug where it mis-detects AVX-capable processors
168 // if the feature has been disabled in firmware. This causes us to crash
169 // in some of the math functions. For now, we disable those optimizations
170 // because Microsoft is not going to fix the problem in VS2013.
171 // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+.
175 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
176 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
177 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
181 _CrtSetReportFile(_CRT_WARN
, _CRTDBG_FILE_STDERR
);
182 _CrtSetReportMode(_CRT_WARN
, _CRTDBG_MODE_FILE
);
183 _CrtSetReportFile(_CRT_ERROR
, _CRTDBG_FILE_STDERR
);
184 _CrtSetReportMode(_CRT_ERROR
, _CRTDBG_MODE_FILE
);
185 _CrtSetReportFile(_CRT_ASSERT
, _CRTDBG_FILE_STDERR
);
186 _CrtSetReportMode(_CRT_ASSERT
, _CRTDBG_MODE_FILE
);
192 // Initialize JSC before getting VM.
193 JSC::initializeThreading();
195 // We can't use destructors in the following code because it uses Windows
196 // Structured Exception Handling
199 res
= realMain(argc
, argv
);
204 static bool testOneRegExp(VM
& vm
, RegExp
* regexp
, RegExpTest
* regExpTest
, bool verbose
, unsigned int lineNumber
)
207 Vector
<int, 32> outVector
;
208 outVector
.resize(regExpTest
->expectVector
.size());
209 int matchResult
= regexp
->match(vm
, regExpTest
->subject
, regExpTest
->offset
, outVector
);
211 if (matchResult
!= regExpTest
->result
) {
214 printf("Line %d: results mismatch - expected %d got %d\n", lineNumber
, regExpTest
->result
, matchResult
);
215 } else if (matchResult
!= -1) {
216 if (outVector
.size() != regExpTest
->expectVector
.size()) {
220 printf("Line %d: output vector size mismatch - expected %Iu got %Iu\n", lineNumber
, regExpTest
->expectVector
.size(), outVector
.size());
222 printf("Line %d: output vector size mismatch - expected %zu got %zu\n", lineNumber
, regExpTest
->expectVector
.size(), outVector
.size());
225 } else if (outVector
.size() % 2) {
229 printf("Line %d: output vector size is odd (%Iu), should be even\n", lineNumber
, outVector
.size());
231 printf("Line %d: output vector size is odd (%zu), should be even\n", lineNumber
, outVector
.size());
235 // Check in pairs since the first value of the pair could be -1 in which case the second doesn't matter.
236 size_t pairCount
= outVector
.size() / 2;
237 for (size_t i
= 0; i
< pairCount
; ++i
) {
238 size_t startIndex
= i
*2;
239 if (outVector
[startIndex
] != regExpTest
->expectVector
[startIndex
]) {
243 printf("Line %d: output vector mismatch at index %Iu - expected %d got %d\n", lineNumber
, startIndex
, regExpTest
->expectVector
[startIndex
], outVector
[startIndex
]);
245 printf("Line %d: output vector mismatch at index %zu - expected %d got %d\n", lineNumber
, startIndex
, regExpTest
->expectVector
[startIndex
], outVector
[startIndex
]);
249 if ((i
> 0) && (regExpTest
->expectVector
[startIndex
] != -1) && (outVector
[startIndex
+1] != regExpTest
->expectVector
[startIndex
+1])) {
253 printf("Line %d: output vector mismatch at index %Iu - expected %d got %d\n", lineNumber
, startIndex
+ 1, regExpTest
->expectVector
[startIndex
+ 1], outVector
[startIndex
+ 1]);
255 printf("Line %d: output vector mismatch at index %zu - expected %d got %d\n", lineNumber
, startIndex
+ 1, regExpTest
->expectVector
[startIndex
+ 1], outVector
[startIndex
+ 1]);
266 static int scanString(char* buffer
, int bufferLength
, StringBuilder
& builder
, char termChar
)
270 for (int i
= 0; i
< bufferLength
; ++i
) {
306 if ((i
+ 4) >= bufferLength
)
308 unsigned int charValue
;
309 if (sscanf(buffer
+i
+1, "%04x", &charValue
) != 1)
311 c
= static_cast<UChar
>(charValue
);
332 static RegExp
* parseRegExpLine(VM
& vm
, char* line
, int lineLength
)
334 StringBuilder pattern
;
339 int i
= scanString(line
+ 1, lineLength
- 1, pattern
, '/') + 1;
341 if ((i
>= lineLength
) || (line
[i
] != '/'))
346 return RegExp::create(vm
, pattern
.toString(), regExpFlags(line
+ i
));
349 static RegExpTest
* parseTestLine(char* line
, int lineLength
)
351 StringBuilder subjectString
;
353 if ((line
[0] != ' ') || (line
[1] != '"'))
356 int i
= scanString(line
+ 2, lineLength
- 2, subjectString
, '"') + 2;
358 if ((i
>= (lineLength
- 2)) || (line
[i
] != '"') || (line
[i
+1] != ',') || (line
[i
+2] != ' '))
365 if (sscanf(line
+ i
, "%d, ", &offset
) != 1)
368 while (line
[i
] && line
[i
] != ' ')
375 if (sscanf(line
+ i
, "%d, ", &matchResult
) != 1)
378 while (line
[i
] && line
[i
] != ' ')
383 if (line
[i
++] != '(')
388 RegExpTest
* result
= new RegExpTest();
390 result
->subject
= subjectString
.toString();
391 result
->offset
= offset
;
392 result
->result
= matchResult
;
394 while (line
[i
] && line
[i
] != ')') {
395 if (sscanf(line
+ i
, "%d, %d", &start
, &end
) != 2) {
400 result
->expectVector
.append(start
);
401 result
->expectVector
.append(end
);
403 while (line
[i
] && (line
[i
] != ',') && (line
[i
] != ')'))
406 while (line
[i
] && (line
[i
] != ',') && (line
[i
] != ')'))
411 if (!line
[i
] || (line
[i
] != ',')) {
421 static bool runFromFiles(GlobalObject
* globalObject
, const Vector
<String
>& files
, bool verbose
)
425 Vector
<char> scriptBuffer
;
427 unsigned failures
= 0;
428 char* lineBuffer
= new char[MaxLineLength
+ 1];
430 VM
& vm
= globalObject
->vm();
433 for (size_t i
= 0; i
< files
.size(); i
++) {
434 FILE* testCasesFile
= fopen(files
[i
].utf8().data(), "rb");
436 if (!testCasesFile
) {
437 printf("Unable to open test data file \"%s\"\n", files
[i
].utf8().data());
442 size_t lineLength
= 0;
444 unsigned int lineNumber
= 0;
446 while ((linePtr
= fgets(&lineBuffer
[0], MaxLineLength
, testCasesFile
))) {
447 lineLength
= strlen(linePtr
);
448 if (linePtr
[lineLength
- 1] == '\n') {
449 linePtr
[lineLength
- 1] = '\0';
454 if (linePtr
[0] == '#')
457 if (linePtr
[0] == '/') {
458 regexp
= parseRegExpLine(vm
, linePtr
, lineLength
);
459 } else if (linePtr
[0] == ' ') {
460 RegExpTest
* regExpTest
= parseTestLine(linePtr
, lineLength
);
462 if (regexp
&& regExpTest
) {
464 if (!testOneRegExp(vm
, regexp
, regExpTest
, verbose
, lineNumber
)) {
466 printf("Failure on line %u\n", lineNumber
);
475 fclose(testCasesFile
);
479 printf("%u tests run, %u failures\n", tests
, failures
);
481 printf("%u tests passed\n", tests
);
485 vm
.dumpSampleData(globalObject
->globalExec());
486 #if ENABLE(REGEXP_TRACING)
487 vm
.dumpRegExpTrace();
492 #define RUNNING_FROM_XCODE 0
494 static NO_RETURN
void printUsageStatement(bool help
= false)
496 fprintf(stderr
, "Usage: regexp_test [options] file\n");
497 fprintf(stderr
, " -h|--help Prints this help message\n");
498 fprintf(stderr
, " -v|--verbose Verbose output\n");
500 exit(help
? EXIT_SUCCESS
: EXIT_FAILURE
);
503 static void parseArguments(int argc
, char** argv
, CommandLine
& options
)
506 for (; i
< argc
; ++i
) {
507 const char* arg
= argv
[i
];
508 if (!strcmp(arg
, "-h") || !strcmp(arg
, "--help"))
509 printUsageStatement(true);
510 if (!strcmp(arg
, "-v") || !strcmp(arg
, "--verbose"))
511 options
.verbose
= true;
513 options
.files
.append(argv
[i
]);
516 for (; i
< argc
; ++i
)
517 options
.arguments
.append(argv
[i
]);
520 int realMain(int argc
, char** argv
)
522 VM
* vm
= &VM::create(LargeHeap
).leakRef();
523 JSLockHolder
locker(vm
);
526 parseArguments(argc
, argv
, options
);
528 GlobalObject
* globalObject
= GlobalObject::create(*vm
, GlobalObject::createStructure(*vm
, jsNull()), options
.arguments
);
529 bool success
= runFromFiles(globalObject
, options
.files
, options
.verbose
);
531 return success
? 0 : 3;
535 extern "C" __declspec(dllexport
) int WINAPI
dllLauncherEntryPoint(int argc
, const char* argv
[])
537 return main(argc
, const_cast<char**>(argv
));