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

Last change on this file since 130303 was 130303, 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 Geoffrey Garen.

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 two static bools, needsDestruction and hasImmortalStructure, that classes can override

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