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

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

Exception stack traces aren't complete when the exception starts in native code
https://bugs.webkit.org/show_bug.cgi?id=84073

Reviewed by Gavin Barraclough.

Source/JavaScriptCore:

Refactored building the stack trace to so that we can construct
it earlier, and don't rely on any prior work performed in the
exception handling machinery. Also updated LLInt and the DFG to
completely initialise the callframes of host function calls.

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::codeOriginIndexForReturn):
(CodeBlock):

  • dfg/DFGOperations.cpp:
  • interpreter/Interpreter.cpp:

(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::addStackTraceIfNecessary):
(JSC):
(JSC::Interpreter::throwException):

  • interpreter/Interpreter.h:

(Interpreter):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • jsc.cpp:

(functionJSCStack):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::handleHostCall):

  • parser/Parser.h:

(JSC::::parse):

  • runtime/Error.cpp:

(JSC::addErrorInfo):
(JSC::throwError):

  • runtime/Error.h:

(JSC):

LayoutTests:

Update tests to include new exception property ordering, and new functions

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

(selfRecursive1): Modified slightly so that we produce consistent traces

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