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

Last change on this file since 128813 was 128813, checked in by [email protected], 13 years ago

Delayed structure sweep can leak structures without bound
https://bugs.webkit.org/show_bug.cgi?id=96546

Reviewed by Gavin Barraclough.

This patch gets rid of the separate Structure allocator in the MarkedSpace and adds two new destructor-only
allocators. We now have separate allocators for our three types of objects: those objects with no destructors,
those objects with destructors and with immortal structures, and those objects with destructors that don't have
immortal structures. All of the objects of the third type (destructors without immortal structures) now
inherit from a new class named JSDestructibleObject (which in turn is a subclass of JSNonFinalObject), which stores
the ClassInfo for these classes at a fixed offset for safe retrieval during sweeping/destruction.

Source/JavaScriptCore:

  • API/JSCallbackConstructor.cpp: Use JSDestructibleObject for JSCallbackConstructor.

(JSC):
(JSC::JSCallbackConstructor::JSCallbackConstructor):

  • API/JSCallbackConstructor.h:

(JSCallbackConstructor):

  • API/JSCallbackObject.cpp: Inherit from JSDestructibleObject for normal JSCallbackObjects and use a finalizer for

JSCallbackObject<JSGlobalObject>, since JSGlobalObject also uses a finalizer.
(JSC):
(JSC::::create): We need to move the create function for JSCallbackObject<JSGlobalObject> out of line so we can add
the finalizer for it. We don't want to add the finalizer is something like finishCreation in case somebody decides
to subclass this. We use this same technique for many other subclasses of JSGlobalObject.
(JSC::::createStructure):

  • API/JSCallbackObject.h:

(JSCallbackObject):
(JSC):

  • API/JSClassRef.cpp: Change all the JSCallbackObject<JSNonFinalObject> to use JSDestructibleObject instead.

(OpaqueJSClass::prototype):

  • API/JSObjectRef.cpp: Ditto.

(JSObjectMake):
(JSObjectGetPrivate):
(JSObjectSetPrivate):
(JSObjectGetPrivateProperty):
(JSObjectSetPrivateProperty):
(JSObjectDeletePrivateProperty):

  • API/JSValueRef.cpp: Ditto.

(JSValueIsObjectOfClass):

  • API/JSWeakObjectMapRefPrivate.cpp: Ditto.
  • JSCTypedArrayStubs.h:

(JSC):

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • dfg/DFGSpeculativeJIT.h: Use the proper allocator type when doing inline allocation in the DFG.

(JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject):
(JSC::DFG::SpeculativeJIT::emitAllocateJSFinalObject):

  • heap/Heap.cpp:

(JSC):

  • heap/Heap.h: Add accessors for the various types of allocators now. Also remove the isSafeToSweepStructures function

since it's always safe to sweep Structures now.
(JSC::Heap::allocatorForObjectWithNormalDestructor):
(JSC::Heap::allocatorForObjectWithImmortalStructureDestructor):
(Heap):
(JSC::Heap::allocateWithNormalDestructor):
(JSC):
(JSC::Heap::allocateWithImmortalStructureDestructor):

  • heap/IncrementalSweeper.cpp: Remove all the logic to detect when it's safe to sweep Structures from the

IncrementalSweeper since it's always safe to sweep Structures now.
(JSC::IncrementalSweeper::IncrementalSweeper):
(JSC::IncrementalSweeper::sweepNextBlock):
(JSC::IncrementalSweeper::startSweeping):
(JSC::IncrementalSweeper::willFinishSweeping):
(JSC):

  • heap/IncrementalSweeper.h:

(IncrementalSweeper):

  • heap/MarkedAllocator.cpp: Remove the logic that was preventing us from sweeping Structures if it wasn't safe. Add

tracking of the specific destructor type of allocator.
(JSC::MarkedAllocator::tryAllocateHelper):
(JSC::MarkedAllocator::allocateBlock):

  • heap/MarkedAllocator.h:

(JSC::MarkedAllocator::destructorType):
(MarkedAllocator):
(JSC::MarkedAllocator::MarkedAllocator):
(JSC::MarkedAllocator::init):

  • heap/MarkedBlock.cpp: Add all the destructor type stuff to MarkedBlocks so that we do the right thing when sweeping.

We also use the stored destructor type to determine the right thing to do in all JSCell::classInfo() calls.
(JSC::MarkedBlock::create):
(JSC::MarkedBlock::MarkedBlock):
(JSC):
(JSC::MarkedBlock::specializedSweep):
(JSC::MarkedBlock::sweep):
(JSC::MarkedBlock::sweepHelper):

  • heap/MarkedBlock.h:

(JSC):
(JSC::MarkedBlock::allocator):
(JSC::MarkedBlock::destructorType):

  • heap/MarkedSpace.cpp: Add the new destructor allocators to MarkedSpace.

(JSC::MarkedSpace::MarkedSpace):
(JSC::MarkedSpace::resetAllocators):
(JSC::MarkedSpace::canonicalizeCellLivenessData):
(JSC::MarkedSpace::isPagedOut):
(JSC::MarkedSpace::freeBlock):

  • heap/MarkedSpace.h:

(MarkedSpace):
(JSC::MarkedSpace::immortalStructureDestructorAllocatorFor):
(JSC::MarkedSpace::normalDestructorAllocatorFor):
(JSC::MarkedSpace::allocateWithImmortalStructureDestructor):
(JSC::MarkedSpace::allocateWithNormalDestructor):
(JSC::MarkedSpace::forEachBlock):

  • heap/SlotVisitor.cpp: Add include because the symbol was needed in an inlined function.
  • jit/JIT.h: Make sure we use the correct allocator when doing inline allocations in the baseline JIT.
  • jit/JITInlineMethods.h:

(JSC::JIT::emitAllocateBasicJSObject):
(JSC::JIT::emitAllocateJSFinalObject):
(JSC::JIT::emitAllocateJSArray):

  • jsc.cpp:

(GlobalObject::create): Add finalizer here since JSGlobalObject needs to use a finalizer instead of inheriting from
JSDestructibleObject.

  • runtime/Arguments.cpp: Inherit from JSDestructibleObject.

(JSC):

  • runtime/Arguments.h:

(Arguments):
(JSC::Arguments::Arguments):

  • runtime/ErrorPrototype.cpp: Added an assert to make sure we have a trivial destructor.

(JSC):

  • runtime/Executable.h: Indicate that all of the Executable* classes have immortal Structures.

(JSC):

  • runtime/InternalFunction.cpp: Inherit from JSDestructibleObject.

(JSC):
(JSC::InternalFunction::InternalFunction):

  • runtime/InternalFunction.h:

(InternalFunction):

  • runtime/JSCell.h: Added the NEEDS_DESTRUCTOR macro to make it easier for classes to indicate that instead of being

allocated in a destructor MarkedAllocator that they will handle their destruction themselves through the
use of a finalizer.
(JSC):
(HasImmortalStructure): New template to help us determine at compile-time if a particular class
should be allocated in the immortal structure MarkedAllocator. The default value is false. In order
to be allocated in the immortal structure allocator, classes must specialize this template. Also added
a macro to make it easier for classes to specialize the template.
(JSC::allocateCell): Use the appropriate allocator depending on the destructor type.

  • runtime/JSDestructibleObject.h: Added. New class that stores the ClassInfo of any subclass so that it can be

accessed safely when the object is being destroyed.
(JSC):
(JSDestructibleObject):
(JSC::JSDestructibleObject::classInfo):
(JSC::JSDestructibleObject::JSDestructibleObject):
(JSC::JSCell::classInfo): Checks the current MarkedBlock to see where it should get the ClassInfo from so that it's always safe.

  • runtime/JSGlobalObject.cpp: JSGlobalObject now uses a finalizer instead of a destructor so that it can avoid forcing all

of its relatives in the inheritance hierarchy (e.g. JSScope) to use destructors as well.
(JSC::JSGlobalObject::reset):

  • runtime/JSGlobalObject.h:

(JSGlobalObject):
(JSC::JSGlobalObject::createRareDataIfNeeded): Since we always create a finalizer now, we don't have to worry about adding one
for the m_rareData field when it's created.
(JSC::JSGlobalObject::create):
(JSC):

  • runtime/JSGlobalThis.h: Inherit from JSDestructibleObject.

(JSGlobalThis):
(JSC::JSGlobalThis::JSGlobalThis):

  • runtime/JSPropertyNameIterator.h: Has an immortal Structure.

(JSC):

  • runtime/JSScope.cpp:

(JSC):

  • runtime/JSString.h: Has an immortal Structure.

(JSC):

  • runtime/JSWrapperObject.h: Inherit from JSDestructibleObject.

(JSWrapperObject):
(JSC::JSWrapperObject::JSWrapperObject):

  • runtime/MathObject.cpp: Cleaning up some of the inheritance stuff.

(JSC):

  • runtime/NameInstance.h: Inherit from JSDestructibleObject.

(NameInstance):

  • runtime/RegExp.h: Has immortal Structure.

(JSC):

  • runtime/RegExpObject.cpp: Inheritance cleanup.

(JSC):

  • runtime/SparseArrayValueMap.h: Has immortal Structure.

(JSC):

  • runtime/Structure.h: Has immortal Structure.

(JSC):

  • runtime/StructureChain.h: Ditto.

(JSC):

  • runtime/SymbolTable.h: Ditto.

(SharedSymbolTable):
(JSC):

Source/WebCore:

No new tests.

  • ForwardingHeaders/runtime/JSDestructableObject.h: Added.
  • bindings/js/JSDOMWrapper.h: Inherits from JSDestructibleObject.

(JSDOMWrapper):
(WebCore::JSDOMWrapper::JSDOMWrapper):

  • bindings/scripts/CodeGeneratorJS.pm: Add finalizers to anything that inherits from JSGlobalObject,

e.g. JSDOMWindow and JSWorkerContexts. For those classes we also need to use the NEEDS_DESTRUCTOR macro.
(GenerateHeader):

  • bridge/objc/objc_runtime.h: Inherit from JSDestructibleObject.

(ObjcFallbackObjectImp):

  • bridge/objc/objc_runtime.mm:

(Bindings):
(JSC::Bindings::ObjcFallbackObjectImp::ObjcFallbackObjectImp):

  • bridge/runtime_array.cpp: Use a finalizer so that JSArray isn't forced to inherit from JSDestructibleObject.

(JSC):
(JSC::RuntimeArray::destroy):

  • bridge/runtime_array.h:

(JSC::RuntimeArray::create):
(JSC):

  • bridge/runtime_object.cpp: Inherit from JSDestructibleObject.

(Bindings):
(JSC::Bindings::RuntimeObject::RuntimeObject):

  • bridge/runtime_object.h:

(RuntimeObject):

  • Property svn:eol-style set to native
File size: 14.2 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 "JSGlobalObject.h"
27#include <errno.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <wtf/text/StringBuilder.h>
32
33#if !OS(WINDOWS)
34#include <unistd.h>
35#endif
36
37#if HAVE(SYS_TIME_H)
38#include <sys/time.h>
39#endif
40
41#if COMPILER(MSVC) && !OS(WINCE)
42#include <crtdbg.h>
43#include <mmsystem.h>
44#include <windows.h>
45#endif
46
47#if PLATFORM(QT)
48#include <QCoreApplication>
49#include <QDateTime>
50#endif
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 = currentTime();
84}
85
86void StopWatch::stop()
87{
88 m_stopTime = currentTime();
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(JSGlobalData&, Structure*, const Vector<String>& arguments);
112
113public:
114 typedef JSGlobalObject Base;
115
116 static GlobalObject* create(JSGlobalData& globalData, Structure* structure, const Vector<String>& arguments)
117 {
118 GlobalObject* globalObject = new (NotNull, allocateCell<GlobalObject>(globalData.heap)) GlobalObject(globalData, structure, arguments);
119 globalData.heap.addFinalizer(globalObject, destroy);
120 return globalObject;
121 }
122
123 static const ClassInfo s_info;
124
125 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
126 {
127 return Structure::create(globalData, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info);
128 }
129
130protected:
131 void finishCreation(JSGlobalData& globalData, const Vector<String>& arguments)
132 {
133 Base::finishCreation(globalData);
134 UNUSED_PARAM(arguments);
135 }
136};
137
138namespace JSC {
139NEEDS_DESTRUCTOR(GlobalObject, false);
140}
141
142COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
143ASSERT_CLASS_FITS_IN_CELL(GlobalObject);
144
145const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
146
147GlobalObject::GlobalObject(JSGlobalData& globalData, Structure* structure, const Vector<String>& arguments)
148 : JSGlobalObject(globalData, structure)
149{
150 finishCreation(globalData, arguments);
151}
152
153// Use SEH for Release builds only to get rid of the crash report dialog
154// (luckily the same tests fail in Release and Debug builds so far). Need to
155// be in a separate main function because the realMain function requires object
156// unwinding.
157
158#if COMPILER(MSVC) && !COMPILER(INTEL) && !defined(_DEBUG) && !OS(WINCE)
159#define TRY __try {
160#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
161#else
162#define TRY
163#define EXCEPT(x)
164#endif
165
166int realMain(int argc, char** argv);
167
168int main(int argc, char** argv)
169{
170#if OS(WINDOWS)
171#if !OS(WINCE)
172 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
173 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
174 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
175 ::SetErrorMode(0);
176#endif
177
178#if defined(_DEBUG)
179 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
180 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
181 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
182 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
183 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
184 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
185#endif
186
187 timeBeginPeriod(1);
188#endif
189
190#if PLATFORM(QT)
191 QCoreApplication app(argc, argv);
192#endif
193
194 // Initialize JSC before getting JSGlobalData.
195 JSC::initializeThreading();
196
197 // We can't use destructors in the following code because it uses Windows
198 // Structured Exception Handling
199 int res = 0;
200 TRY
201 res = realMain(argc, argv);
202 EXCEPT(res = 3)
203 return res;
204}
205
206static bool testOneRegExp(JSGlobalData& globalData, RegExp* regexp, RegExpTest* regExpTest, bool verbose, unsigned int lineNumber)
207{
208 bool result = true;
209 Vector<int, 32> outVector;
210 outVector.resize(regExpTest->expectVector.size());
211 int matchResult = regexp->match(globalData, regExpTest->subject, regExpTest->offset, outVector);
212
213 if (matchResult != regExpTest->result) {
214 result = false;
215 if (verbose)
216 printf("Line %d: results mismatch - expected %d got %d\n", lineNumber, regExpTest->result, matchResult);
217 } else if (matchResult != -1) {
218 if (outVector.size() != regExpTest->expectVector.size()) {
219 result = false;
220 if (verbose)
221 printf("Line %d: output vector size mismatch - expected %lu got %lu\n", lineNumber, regExpTest->expectVector.size(), outVector.size());
222 } else if (outVector.size() % 2) {
223 result = false;
224 if (verbose)
225 printf("Line %d: output vector size is odd (%lu), should be even\n", lineNumber, outVector.size());
226 } else {
227 // Check in pairs since the first value of the pair could be -1 in which case the second doesn't matter.
228 size_t pairCount = outVector.size() / 2;
229 for (size_t i = 0; i < pairCount; ++i) {
230 size_t startIndex = i*2;
231 if (outVector[startIndex] != regExpTest->expectVector[startIndex]) {
232 result = false;
233 if (verbose)
234 printf("Line %d: output vector mismatch at index %lu - expected %d got %d\n", lineNumber, startIndex, regExpTest->expectVector[startIndex], outVector[startIndex]);
235 }
236 if ((i > 0) && (regExpTest->expectVector[startIndex] != -1) && (outVector[startIndex+1] != regExpTest->expectVector[startIndex+1])) {
237 result = false;
238 if (verbose)
239 printf("Line %d: output vector mismatch at index %lu - expected %d got %d\n", lineNumber, startIndex+1, regExpTest->expectVector[startIndex+1], outVector[startIndex+1]);
240 }
241 }
242 }
243 }
244
245 return result;
246}
247
248static int scanString(char* buffer, int bufferLength, StringBuilder& builder, char termChar)
249{
250 bool escape = false;
251
252 for (int i = 0; i < bufferLength; ++i) {
253 UChar c = buffer[i];
254
255 if (escape) {
256 switch (c) {
257 case '0':
258 c = '\0';
259 break;
260 case 'a':
261 c = '\a';
262 break;
263 case 'b':
264 c = '\b';
265 break;
266 case 'f':
267 c = '\f';
268 break;
269 case 'n':
270 c = '\n';
271 break;
272 case 'r':
273 c = '\r';
274 break;
275 case 't':
276 c = '\t';
277 break;
278 case 'v':
279 c = '\v';
280 break;
281 case '\\':
282 c = '\\';
283 break;
284 case '?':
285 c = '\?';
286 break;
287 case 'u':
288 if ((i + 4) >= bufferLength)
289 return -1;
290 unsigned int charValue;
291 if (sscanf(buffer+i+1, "%04x", &charValue) != 1)
292 return -1;
293 c = static_cast<UChar>(charValue);
294 i += 4;
295 break;
296 }
297
298 builder.append(c);
299 escape = false;
300 } else {
301 if (c == termChar)
302 return i;
303
304 if (c == '\\')
305 escape = true;
306 else
307 builder.append(c);
308 }
309 }
310
311 return -1;
312}
313
314static RegExp* parseRegExpLine(JSGlobalData& globalData, char* line, int lineLength)
315{
316 StringBuilder pattern;
317
318 if (line[0] != '/')
319 return 0;
320
321 int i = scanString(line + 1, lineLength - 1, pattern, '/') + 1;
322
323 if ((i >= lineLength) || (line[i] != '/'))
324 return 0;
325
326 ++i;
327
328 return RegExp::create(globalData, pattern.toString(), regExpFlags(line + i));
329}
330
331static RegExpTest* parseTestLine(char* line, int lineLength)
332{
333 StringBuilder subjectString;
334
335 if ((line[0] != ' ') || (line[1] != '"'))
336 return 0;
337
338 int i = scanString(line + 2, lineLength - 2, subjectString, '"') + 2;
339
340 if ((i >= (lineLength - 2)) || (line[i] != '"') || (line[i+1] != ',') || (line[i+2] != ' '))
341 return 0;
342
343 i += 3;
344
345 int offset;
346
347 if (sscanf(line + i, "%d, ", &offset) != 1)
348 return 0;
349
350 while (line[i] && line[i] != ' ')
351 ++i;
352
353 ++i;
354
355 int matchResult;
356
357 if (sscanf(line + i, "%d, ", &matchResult) != 1)
358 return 0;
359
360 while (line[i] && line[i] != ' ')
361 ++i;
362
363 ++i;
364
365 if (line[i++] != '(')
366 return 0;
367
368 int start, end;
369
370 RegExpTest* result = new RegExpTest();
371
372 result->subject = subjectString.toString();
373 result->offset = offset;
374 result->result = matchResult;
375
376 while (line[i] && line[i] != ')') {
377 if (sscanf(line + i, "%d, %d", &start, &end) != 2) {
378 delete result;
379 return 0;
380 }
381
382 result->expectVector.append(start);
383 result->expectVector.append(end);
384
385 while (line[i] && (line[i] != ',') && (line[i] != ')'))
386 i++;
387 i++;
388 while (line[i] && (line[i] != ',') && (line[i] != ')'))
389 i++;
390
391 if (line[i] == ')')
392 break;
393 if (!line[i] || (line[i] != ',')) {
394 delete result;
395 return 0;
396 }
397 i++;
398 }
399
400 return result;
401}
402
403static bool runFromFiles(GlobalObject* globalObject, const Vector<String>& files, bool verbose)
404{
405 String script;
406 String fileName;
407 Vector<char> scriptBuffer;
408 unsigned tests = 0;
409 unsigned failures = 0;
410 char* lineBuffer = new char[MaxLineLength + 1];
411
412 JSGlobalData& globalData = globalObject->globalData();
413
414 bool success = true;
415 for (size_t i = 0; i < files.size(); i++) {
416 FILE* testCasesFile = fopen(files[i].utf8().data(), "rb");
417
418 if (!testCasesFile) {
419 printf("Unable to open test data file \"%s\"\n", files[i].utf8().data());
420 continue;
421 }
422
423 RegExp* regexp = 0;
424 size_t lineLength = 0;
425 char* linePtr = 0;
426 unsigned int lineNumber = 0;
427
428 while ((linePtr = fgets(&lineBuffer[0], MaxLineLength, testCasesFile))) {
429 lineLength = strlen(linePtr);
430 if (linePtr[lineLength - 1] == '\n') {
431 linePtr[lineLength - 1] = '\0';
432 --lineLength;
433 }
434 ++lineNumber;
435
436 if (linePtr[0] == '#')
437 continue;
438
439 if (linePtr[0] == '/') {
440 regexp = parseRegExpLine(globalData, linePtr, lineLength);
441 } else if (linePtr[0] == ' ') {
442 RegExpTest* regExpTest = parseTestLine(linePtr, lineLength);
443
444 if (regexp && regExpTest) {
445 ++tests;
446 if (!testOneRegExp(globalData, regexp, regExpTest, verbose, lineNumber)) {
447 failures++;
448 printf("Failure on line %u\n", lineNumber);
449 }
450 }
451
452 if (regExpTest)
453 delete regExpTest;
454 }
455 }
456
457 fclose(testCasesFile);
458 }
459
460 if (failures)
461 printf("%u tests run, %u failures\n", tests, failures);
462 else
463 printf("%u tests passed\n", tests);
464
465 delete[] lineBuffer;
466
467 globalData.dumpSampleData(globalObject->globalExec());
468#if ENABLE(REGEXP_TRACING)
469 globalData.dumpRegExpTrace();
470#endif
471 return success;
472}
473
474#define RUNNING_FROM_XCODE 0
475
476static NO_RETURN void printUsageStatement(bool help = false)
477{
478 fprintf(stderr, "Usage: regexp_test [options] file\n");
479 fprintf(stderr, " -h|--help Prints this help message\n");
480 fprintf(stderr, " -v|--verbose Verbose output\n");
481
482 exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
483}
484
485static void parseArguments(int argc, char** argv, CommandLine& options)
486{
487 int i = 1;
488 for (; i < argc; ++i) {
489 const char* arg = argv[i];
490 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
491 printUsageStatement(true);
492 if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose"))
493 options.verbose = true;
494 else
495 options.files.append(argv[i]);
496 }
497
498 for (; i < argc; ++i)
499 options.arguments.append(argv[i]);
500}
501
502int realMain(int argc, char** argv)
503{
504 RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap);
505 JSLockHolder lock(globalData.get());
506
507 CommandLine options;
508 parseArguments(argc, argv, options);
509
510 GlobalObject* globalObject = GlobalObject::create(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.arguments);
511 bool success = runFromFiles(globalObject, options.files, options.verbose);
512
513 return success ? 0 : 3;
514}
Note: See TracBrowser for help on using the repository browser.