source: webkit/trunk/Source/JavaScriptCore/jsc.cpp@ 108112

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

Implement Error.stack
https://bugs.webkit.org/show_bug.cgi?id=66994

Reviewed by Gavin Barraclough.

Source/JavaScriptCore:

Implement support for stack traces on exception objects. This is a rewrite
of the core portion of the last stack walking logic, but the mechanical work
of adding the information to an exception comes from the original work by
Juan Carlos Montemayor Elosua.

  • interpreter/Interpreter.cpp:

(JSC::getCallerInfo):
(JSC):
(JSC::getSourceURLFromCallFrame):
(JSC::getStackFrameCodeType):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::throwException):
(JSC::Interpreter::privateExecute):

  • interpreter/Interpreter.h:

(JSC):
(StackFrame):
(JSC::StackFrame::toString):
(Interpreter):

  • jsc.cpp:

(GlobalObject::finishCreation):
(functionJSCStack):

  • parser/Nodes.h:

(JSC::FunctionBodyNode::setInferredName):

  • parser/Parser.h:

(JSC::::parse):

  • runtime/CommonIdentifiers.h:
  • runtime/Error.cpp:

(JSC::addErrorInfo):

  • runtime/Error.h:

(JSC):

LayoutTests:

Add testcases for producing a stack trace on exception objects.

  • fast/js/exception-properties-expected.txt:
  • fast/js/script-tests/exception-properties.js:
  • fast/js/script-tests/stack-trace.js: Added.

(printStack):
(hostThrower):
(callbacker):
(outer):
(inner):
(evaler):
(normalOuter):
(normalInner):
(scripterInner):
(scripterOuter):
(selfRecursive1):
(selfRecursive2):
(selfRecursive3):
(throwError):
(object.get getter1.o.valueOf):
(object.get getter1):
(object.get getter2):
(object.get getter3.o2.valueOf):
(object.get getter3):
(object.nonInlineable.callCount):
(object.nonInlineable):
(object.inlineable):
(yetAnotherInlinedCall):
(makeInlinableCall):
(.try.g):
(h):
(mapTest):
(mapTestDriver):
(dfgFunction):
(try.f):

  • fast/js/stack-trace-expected.txt: Added.
  • fast/js/stack-trace.html: Added.
  • Property svn:eol-style set to native
File size: 21.7 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2006 Bjoern Graf ([email protected])
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24
25#include "BytecodeGenerator.h"
26#include "Completion.h"
27#include "CurrentTime.h"
28#include "ExceptionHelpers.h"
29#include "InitializeThreading.h"
30#include "Interpreter.h"
31#include "JSArray.h"
32#include "JSFunction.h"
33#include "JSLock.h"
34#include "JSString.h"
35#include "MainThread.h"
36#include "SamplingTool.h"
37#include <math.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41
42#if !OS(WINDOWS)
43#include <unistd.h>
44#endif
45
46#if HAVE(READLINE)
47// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
48// We #define it to something else to avoid this conflict.
49#define Function ReadlineFunction
50#include <readline/history.h>
51#include <readline/readline.h>
52#undef Function
53#endif
54
55#if HAVE(SYS_TIME_H)
56#include <sys/time.h>
57#endif
58
59#if HAVE(SIGNAL_H)
60#include <signal.h>
61#endif
62
63#if COMPILER(MSVC) && !OS(WINCE)
64#include <crtdbg.h>
65#include <mmsystem.h>
66#include <windows.h>
67#endif
68
69#if PLATFORM(QT)
70#include <QCoreApplication>
71#include <QDateTime>
72#endif
73
74using namespace JSC;
75using namespace WTF;
76
77static void cleanupGlobalData(JSGlobalData*);
78static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer);
79
80static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
81static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
82static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
83static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
84#ifndef NDEBUG
85static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
86#endif
87static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
88static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
89static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
90static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
91static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
92static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
93static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
94
95#if ENABLE(SAMPLING_FLAGS)
96static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
97static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
98#endif
99
100struct Script {
101 bool isFile;
102 char* argument;
103
104 Script(bool isFile, char *argument)
105 : isFile(isFile)
106 , argument(argument)
107 {
108 }
109};
110
111struct CommandLine {
112 CommandLine()
113 : interactive(false)
114 , dump(false)
115 {
116 }
117
118 bool interactive;
119 bool dump;
120 Vector<Script> scripts;
121 Vector<UString> arguments;
122};
123
124static const char interactivePrompt[] = "> ";
125
126class StopWatch {
127public:
128 void start();
129 void stop();
130 long getElapsedMS(); // call stop() first
131
132private:
133 double m_startTime;
134 double m_stopTime;
135};
136
137void StopWatch::start()
138{
139 m_startTime = currentTime();
140}
141
142void StopWatch::stop()
143{
144 m_stopTime = currentTime();
145}
146
147long StopWatch::getElapsedMS()
148{
149 return static_cast<long>((m_stopTime - m_startTime) * 1000);
150}
151
152class GlobalObject : public JSGlobalObject {
153private:
154 GlobalObject(JSGlobalData&, Structure*);
155
156public:
157 typedef JSGlobalObject Base;
158
159 static GlobalObject* create(JSGlobalData& globalData, Structure* structure, const Vector<UString>& arguments)
160 {
161 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(globalData.heap)) GlobalObject(globalData, structure);
162 object->finishCreation(globalData, arguments);
163 return object;
164 }
165
166 static const ClassInfo s_info;
167
168 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
169 {
170 return Structure::create(globalData, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info);
171 }
172
173protected:
174 void finishCreation(JSGlobalData& globalData, const Vector<UString>& arguments)
175 {
176 Base::finishCreation(globalData);
177
178 addFunction(globalData, "debug", functionDebug, 1);
179 addFunction(globalData, "print", functionPrint, 1);
180 addFunction(globalData, "quit", functionQuit, 0);
181 addFunction(globalData, "gc", functionGC, 0);
182#ifndef NDEBUG
183 addFunction(globalData, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
184#endif
185 addFunction(globalData, "version", functionVersion, 1);
186 addFunction(globalData, "run", functionRun, 1);
187 addFunction(globalData, "load", functionLoad, 1);
188 addFunction(globalData, "checkSyntax", functionCheckSyntax, 1);
189 addFunction(globalData, "jscStack", functionJSCStack, 1);
190 addFunction(globalData, "readline", functionReadline, 0);
191 addFunction(globalData, "preciseTime", functionPreciseTime, 0);
192#if ENABLE(SAMPLING_FLAGS)
193 addFunction(globalData, "setSamplingFlags", functionSetSamplingFlags, 1);
194 addFunction(globalData, "clearSamplingFlags", functionClearSamplingFlags, 1);
195#endif
196
197 JSObject* array = constructEmptyArray(globalExec());
198 for (size_t i = 0; i < arguments.size(); ++i)
199 array->methodTable()->putByIndex(array, globalExec(), i, jsString(globalExec(), arguments[i]));
200 putDirect(globalData, Identifier(globalExec(), "arguments"), array);
201 }
202
203 void addFunction(JSGlobalData& globalData, const char* name, NativeFunction function, unsigned arguments)
204 {
205 Identifier identifier(globalExec(), name);
206 putDirect(globalData, identifier, JSFunction::create(globalExec(), this, arguments, identifier, function));
207 }
208};
209COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
210ASSERT_CLASS_FITS_IN_CELL(GlobalObject);
211
212const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
213
214GlobalObject::GlobalObject(JSGlobalData& globalData, Structure* structure)
215 : JSGlobalObject(globalData, structure)
216{
217}
218
219static inline SourceCode jscSource(const char* utf8, const UString& filename)
220{
221 // Find the the first non-ascii character, or nul.
222 const char* pos = utf8;
223 while (*pos > 0)
224 pos++;
225 size_t asciiLength = pos - utf8;
226
227 // Fast case - string is all ascii.
228 if (!*pos)
229 return makeSource(UString(utf8, asciiLength), filename);
230
231 // Slow case - contains non-ascii characters, use fromUTF8WithLatin1Fallback.
232 ASSERT(*pos < 0);
233 ASSERT(strlen(utf8) == asciiLength + strlen(pos));
234 String source = String::fromUTF8WithLatin1Fallback(utf8, asciiLength + strlen(pos));
235 return makeSource(source.impl(), filename);
236}
237
238EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
239{
240 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
241 if (i)
242 putchar(' ');
243
244 printf("%s", exec->argument(i).toString(exec)->value(exec).utf8().data());
245 }
246
247 putchar('\n');
248 fflush(stdout);
249 return JSValue::encode(jsUndefined());
250}
251
252EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
253{
254 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
255 return JSValue::encode(jsUndefined());
256}
257
258EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
259{
260 String trace = "--> Stack trace:\n";
261 Vector<StackFrame> stackTrace;
262 Interpreter::getStackTrace(&exec->globalData(), -1, stackTrace);
263 int i = 0;
264
265 for (Vector<StackFrame>::iterator iter = stackTrace.begin(); iter < stackTrace.end(); iter++) {
266 StackFrame level = *iter;
267 trace += String::format(" %i %s\n", i, level.toString(exec).utf8().data());
268 i++;
269 }
270 fprintf(stderr, "%s", trace.utf8().data());
271 return JSValue::encode(jsUndefined());
272}
273
274EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
275{
276 JSLock lock(SilenceAssertionsOnly);
277 exec->heap()->collectAllGarbage();
278 return JSValue::encode(jsUndefined());
279}
280
281#ifndef NDEBUG
282EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
283{
284 JSLock lock(SilenceAssertionsOnly);
285 exec->globalData().releaseExecutableMemory();
286 return JSValue::encode(jsUndefined());
287}
288#endif
289
290EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
291{
292 // We need this function for compatibility with the Mozilla JS tests but for now
293 // we don't actually do any version-specific handling
294 return JSValue::encode(jsUndefined());
295}
296
297EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
298{
299 UString fileName = exec->argument(0).toString(exec)->value(exec);
300 Vector<char> script;
301 if (!fillBufferWithContentsOfFile(fileName, script))
302 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
303
304 GlobalObject* globalObject = GlobalObject::create(exec->globalData(), GlobalObject::createStructure(exec->globalData(), jsNull()), Vector<UString>());
305
306 StopWatch stopWatch;
307 stopWatch.start();
308 evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script.data(), fileName));
309 stopWatch.stop();
310
311 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
312}
313
314EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
315{
316 UString fileName = exec->argument(0).toString(exec)->value(exec);
317 Vector<char> script;
318 if (!fillBufferWithContentsOfFile(fileName, script))
319 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
320
321 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
322
323 JSValue evaluationException;
324 JSValue result = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
325 if (evaluationException)
326 throwError(exec, evaluationException);
327 return JSValue::encode(result);
328}
329
330EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
331{
332 UString fileName = exec->argument(0).toString(exec)->value(exec);
333 Vector<char> script;
334 if (!fillBufferWithContentsOfFile(fileName, script))
335 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
336
337 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
338
339 StopWatch stopWatch;
340 stopWatch.start();
341
342 JSValue syntaxException;
343 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
344 stopWatch.stop();
345
346 if (!validSyntax)
347 throwError(exec, syntaxException);
348 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
349}
350
351#if ENABLE(SAMPLING_FLAGS)
352EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
353{
354 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
355 unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
356 if ((flag >= 1) && (flag <= 32))
357 SamplingFlags::setFlag(flag);
358 }
359 return JSValue::encode(jsNull());
360}
361
362EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
363{
364 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
365 unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
366 if ((flag >= 1) && (flag <= 32))
367 SamplingFlags::clearFlag(flag);
368 }
369 return JSValue::encode(jsNull());
370}
371#endif
372
373EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
374{
375 Vector<char, 256> line;
376 int c;
377 while ((c = getchar()) != EOF) {
378 // FIXME: Should we also break on \r?
379 if (c == '\n')
380 break;
381 line.append(c);
382 }
383 line.append('\0');
384 return JSValue::encode(jsString(exec, line.data()));
385}
386
387EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
388{
389 return JSValue::encode(jsNumber(currentTime()));
390}
391
392EncodedJSValue JSC_HOST_CALL functionQuit(ExecState* exec)
393{
394 // Technically, destroying the heap in the middle of JS execution is a no-no,
395 // but we want to maintain compatibility with the Mozilla test suite, so
396 // we pretend that execution has terminated to avoid ASSERTs, then tear down the heap.
397 exec->globalData().dynamicGlobalObject = 0;
398
399 cleanupGlobalData(&exec->globalData());
400 exit(EXIT_SUCCESS);
401
402#if COMPILER(MSVC) && OS(WINCE)
403 // Without this, Visual Studio will complain that this method does not return a value.
404 return JSValue::encode(jsUndefined());
405#endif
406}
407
408// Use SEH for Release builds only to get rid of the crash report dialog
409// (luckily the same tests fail in Release and Debug builds so far). Need to
410// be in a separate main function because the jscmain function requires object
411// unwinding.
412
413#if COMPILER(MSVC) && !COMPILER(INTEL) && !defined(_DEBUG) && !OS(WINCE)
414#define TRY __try {
415#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
416#else
417#define TRY
418#define EXCEPT(x)
419#endif
420
421int jscmain(int argc, char** argv, JSGlobalData*);
422
423int main(int argc, char** argv)
424{
425#if OS(WINDOWS)
426#if !OS(WINCE)
427 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
428 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
429 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
430 ::SetErrorMode(0);
431#endif
432
433#if defined(_DEBUG)
434 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
435 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
436 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
437 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
438 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
439 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
440#endif
441
442 timeBeginPeriod(1);
443#endif
444
445#if PLATFORM(QT)
446 QCoreApplication app(argc, argv);
447#endif
448
449 // Initialize JSC before getting JSGlobalData.
450#if ENABLE(SAMPLING_REGIONS)
451 WTF::initializeMainThread();
452#endif
453 JSC::initializeThreading();
454
455 // We can't use destructors in the following code because it uses Windows
456 // Structured Exception Handling
457 int res = 0;
458 JSGlobalData* globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap).leakRef();
459 TRY
460 res = jscmain(argc, argv, globalData);
461 EXCEPT(res = 3)
462
463 cleanupGlobalData(globalData);
464 return res;
465}
466
467static void cleanupGlobalData(JSGlobalData* globalData)
468{
469 JSLock lock(SilenceAssertionsOnly);
470 globalData->clearBuiltinStructures();
471 globalData->heap.destroy();
472 globalData->deref();
473}
474
475static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
476{
477 const char* script;
478 UString fileName;
479 Vector<char> scriptBuffer;
480
481 if (dump)
482 BytecodeGenerator::setDumpsGeneratedCode(true);
483
484 JSGlobalData& globalData = globalObject->globalData();
485
486#if ENABLE(SAMPLING_FLAGS)
487 SamplingFlags::start();
488#endif
489
490 bool success = true;
491 for (size_t i = 0; i < scripts.size(); i++) {
492 if (scripts[i].isFile) {
493 fileName = scripts[i].argument;
494 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
495 return false; // fail early so we can catch missing files
496 script = scriptBuffer.data();
497 } else {
498 script = scripts[i].argument;
499 fileName = "[Command Line]";
500 }
501
502 globalData.startSampling();
503
504 JSValue evaluationException;
505 JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script, fileName), JSValue(), &evaluationException);
506 success = success && !evaluationException;
507 if (dump) {
508 if (evaluationException)
509 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
510 else
511 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
512 }
513
514 globalData.stopSampling();
515 globalObject->globalExec()->clearException();
516 }
517
518#if ENABLE(SAMPLING_FLAGS)
519 SamplingFlags::stop();
520#endif
521#if ENABLE(SAMPLING_REGIONS)
522 SamplingRegion::dump();
523#endif
524 globalData.dumpSampleData(globalObject->globalExec());
525#if ENABLE(SAMPLING_COUNTERS)
526 AbstractSamplingCounter::dump();
527#endif
528#if ENABLE(REGEXP_TRACING)
529 globalData.dumpRegExpTrace();
530#endif
531 return success;
532}
533
534#define RUNNING_FROM_XCODE 0
535
536static void runInteractive(GlobalObject* globalObject)
537{
538 UString interpreterName("Interpreter");
539
540 while (true) {
541#if HAVE(READLINE) && !RUNNING_FROM_XCODE
542 char* line = readline(interactivePrompt);
543 if (!line)
544 break;
545 if (line[0])
546 add_history(line);
547 JSValue evaluationException;
548 JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(line, interpreterName), JSValue(), &evaluationException);
549 free(line);
550#else
551 printf("%s", interactivePrompt);
552 Vector<char, 256> line;
553 int c;
554 while ((c = getchar()) != EOF) {
555 // FIXME: Should we also break on \r?
556 if (c == '\n')
557 break;
558 line.append(c);
559 }
560 if (line.isEmpty())
561 break;
562 line.append('\0');
563
564 JSValue evaluationException;
565 JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
566#endif
567 if (evaluationException)
568 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
569 else
570 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
571
572 globalObject->globalExec()->clearException();
573 }
574 printf("\n");
575}
576
577static NO_RETURN void printUsageStatement(JSGlobalData* globalData, bool help = false)
578{
579 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
580 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
581 fprintf(stderr, " -e Evaluate argument as script code\n");
582 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
583 fprintf(stderr, " -h|--help Prints this help message\n");
584 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
585#if HAVE(SIGNAL_H)
586 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
587#endif
588
589 cleanupGlobalData(globalData);
590 exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
591}
592
593static void parseArguments(int argc, char** argv, CommandLine& options, JSGlobalData* globalData)
594{
595 int i = 1;
596 for (; i < argc; ++i) {
597 const char* arg = argv[i];
598 if (!strcmp(arg, "-f")) {
599 if (++i == argc)
600 printUsageStatement(globalData);
601 options.scripts.append(Script(true, argv[i]));
602 continue;
603 }
604 if (!strcmp(arg, "-e")) {
605 if (++i == argc)
606 printUsageStatement(globalData);
607 options.scripts.append(Script(false, argv[i]));
608 continue;
609 }
610 if (!strcmp(arg, "-i")) {
611 options.interactive = true;
612 continue;
613 }
614 if (!strcmp(arg, "-d")) {
615 options.dump = true;
616 continue;
617 }
618 if (!strcmp(arg, "-s")) {
619#if HAVE(SIGNAL_H)
620 signal(SIGILL, _exit);
621 signal(SIGFPE, _exit);
622 signal(SIGBUS, _exit);
623 signal(SIGSEGV, _exit);
624#endif
625 continue;
626 }
627 if (!strcmp(arg, "--")) {
628 ++i;
629 break;
630 }
631 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
632 printUsageStatement(globalData, true);
633 options.scripts.append(Script(true, argv[i]));
634 }
635
636 if (options.scripts.isEmpty())
637 options.interactive = true;
638
639 for (; i < argc; ++i)
640 options.arguments.append(argv[i]);
641}
642
643int jscmain(int argc, char** argv, JSGlobalData* globalData)
644{
645 JSLock lock(SilenceAssertionsOnly);
646
647 CommandLine options;
648 parseArguments(argc, argv, options, globalData);
649
650 GlobalObject* globalObject = GlobalObject::create(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.arguments);
651 bool success = runWithScripts(globalObject, options.scripts, options.dump);
652 if (options.interactive && success)
653 runInteractive(globalObject);
654
655 return success ? 0 : 3;
656}
657
658static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer)
659{
660 FILE* f = fopen(fileName.utf8().data(), "r");
661 if (!f) {
662 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
663 return false;
664 }
665
666 size_t bufferSize = 0;
667 size_t bufferCapacity = 1024;
668
669 buffer.resize(bufferCapacity);
670
671 while (!feof(f) && !ferror(f)) {
672 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
673 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
674 bufferCapacity *= 2;
675 buffer.resize(bufferCapacity);
676 }
677 }
678 fclose(f);
679 buffer[bufferSize] = '\0';
680
681 if (buffer[0] == '#' && buffer[1] == '!')
682 buffer[0] = buffer[1] = '/';
683
684 return true;
685}
Note: See TracBrowser for help on using the repository browser.