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

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

Converting StackIterator to a callback interface.
https://bugs.webkit.org/show_bug.cgi?id=120564.

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

  • API/JSContextRef.cpp:

(BacktraceFunctor::BacktraceFunctor):
(BacktraceFunctor::operator()):
(JSContextCreateBacktrace):

  • interpreter/CallFrame.cpp:
  • interpreter/CallFrame.h:
  • interpreter/Interpreter.cpp:

(JSC::DumpRegisterFunctor::DumpRegisterFunctor):
(JSC::DumpRegisterFunctor::operator()):
(JSC::Interpreter::dumpRegisters):
(JSC::unwindCallFrame):
(JSC::GetStackTraceFunctor::GetStackTraceFunctor):
(JSC::GetStackTraceFunctor::operator()):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::stackTraceAsString):
(JSC::UnwindFunctor::UnwindFunctor):
(JSC::UnwindFunctor::operator()):
(JSC::Interpreter::unwind):

  • interpreter/Interpreter.h:
  • interpreter/StackIterator.cpp:

(JSC::StackIterator::numberOfFrames):
(JSC::StackIterator::gotoFrameAtIndex):
(JSC::StackIterator::gotoNextFrameWithFilter):
(JSC::StackIterator::resetIterator):
(JSC::StackIterator::Frame::print):
(debugPrintCallFrame):
(DebugPrintStackFunctor::operator()):
(debugPrintStack): Added for debugging convenience.

  • interpreter/StackIterator.h:

(JSC::StackIterator::Frame::index):
(JSC::StackIterator::iterate):

  • jsc.cpp:

(FunctionJSCStackFunctor::FunctionJSCStackFunctor):
(FunctionJSCStackFunctor::operator()):
(functionJSCStack):

  • profiler/ProfileGenerator.cpp:

(JSC::AddParentForConsoleStartFunctor::AddParentForConsoleStartFunctor):
(JSC::AddParentForConsoleStartFunctor::foundParent):
(JSC::AddParentForConsoleStartFunctor::operator()):
(JSC::ProfileGenerator::addParentForConsoleStart):

  • runtime/JSFunction.cpp:

(JSC::RetrieveArgumentsFunctor::RetrieveArgumentsFunctor):
(JSC::RetrieveArgumentsFunctor::result):
(JSC::RetrieveArgumentsFunctor::operator()):
(JSC::retrieveArguments):
(JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor):
(JSC::RetrieveCallerFunctionFunctor::result):
(JSC::RetrieveCallerFunctionFunctor::operator()):
(JSC::retrieveCallerFunction):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::GlobalFuncProtoGetterFunctor::GlobalFuncProtoGetterFunctor):
(JSC::GlobalFuncProtoGetterFunctor::result):
(JSC::GlobalFuncProtoGetterFunctor::operator()):
(JSC::globalFuncProtoGetter):
(JSC::GlobalFuncProtoSetterFunctor::GlobalFuncProtoSetterFunctor):
(JSC::GlobalFuncProtoSetterFunctor::allowsAccess):
(JSC::GlobalFuncProtoSetterFunctor::operator()):
(JSC::globalFuncProtoSetter):

  • runtime/ObjectConstructor.cpp:

(JSC::ObjectConstructorGetPrototypeOfFunctor::ObjectConstructorGetPrototypeOfFunctor):
(JSC::ObjectConstructorGetPrototypeOfFunctor::result):
(JSC::ObjectConstructorGetPrototypeOfFunctor::operator()):
(JSC::objectConstructorGetPrototypeOf):

Source/WebCore:

No new tests.

  • bindings/js/JSXMLHttpRequestCustom.cpp:

(WebCore::SendFunctor::SendFunctor):
(WebCore::SendFunctor::hasViableFrame):
(WebCore::SendFunctor::operator()):
(WebCore::JSXMLHttpRequest::send):

  • bindings/js/ScriptCallStackFactory.cpp:

(WebCore::CreateScriptCallStackFunctor::CreateScriptCallStackFunctor):
(WebCore::CreateScriptCallStackFunctor::operator()):
(WebCore::createScriptCallStack):
(WebCore::CreateScriptCallStackForConsoleFunctor::CreateScriptCallStackForConsoleFunctor):
(WebCore::CreateScriptCallStackForConsoleFunctor::operator()):

  • Property svn:eol-style set to native
File size: 26.6 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012, 2013 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 "APIShims.h"
26#include "ButterflyInlines.h"
27#include "BytecodeGenerator.h"
28#include "CallFrameInlines.h"
29#include "Completion.h"
30#include "CopiedSpaceInlines.h"
31#include "ExceptionHelpers.h"
32#include "HeapStatistics.h"
33#include "InitializeThreading.h"
34#include "Interpreter.h"
35#include "JSArray.h"
36#include "JSFunction.h"
37#include "JSLock.h"
38#include "JSProxy.h"
39#include "JSString.h"
40#include "Operations.h"
41#include "SamplingTool.h"
42#include "StackIterator.h"
43#include "StructureRareDataInlines.h"
44#include <math.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <wtf/CurrentTime.h>
49#include <wtf/MainThread.h>
50#include <wtf/StringPrintStream.h>
51#include <wtf/text/StringBuilder.h>
52
53#if !OS(WINDOWS)
54#include <unistd.h>
55#endif
56
57#if HAVE(READLINE)
58// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
59// We #define it to something else to avoid this conflict.
60#define Function ReadlineFunction
61#include <readline/history.h>
62#include <readline/readline.h>
63#undef Function
64#endif
65
66#if HAVE(SYS_TIME_H)
67#include <sys/time.h>
68#endif
69
70#if HAVE(SIGNAL_H)
71#include <signal.h>
72#endif
73
74#if COMPILER(MSVC) && !OS(WINCE)
75#include <crtdbg.h>
76#include <mmsystem.h>
77#include <windows.h>
78#endif
79
80#if PLATFORM(QT)
81#include <QCoreApplication>
82#include <QDateTime>
83#endif
84
85#if PLATFORM(IOS)
86#include <fenv.h>
87#include <arm/arch.h>
88#endif
89
90#if PLATFORM(BLACKBERRY)
91#include <BlackBerryPlatformLog.h>
92#endif
93
94#if PLATFORM(EFL)
95#include <Ecore.h>
96#endif
97
98using namespace JSC;
99using namespace WTF;
100
101static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
102
103static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
104static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
105static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
106static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
107static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
108#ifndef NDEBUG
109static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
110static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
111#endif
112static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
113static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
114static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
115static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
116static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
117static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
118static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
119
120#if ENABLE(SAMPLING_FLAGS)
121static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
122static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
123#endif
124
125struct Script {
126 bool isFile;
127 char* argument;
128
129 Script(bool isFile, char *argument)
130 : isFile(isFile)
131 , argument(argument)
132 {
133 }
134};
135
136class CommandLine {
137public:
138 CommandLine(int argc, char** argv)
139 : m_interactive(false)
140 , m_dump(false)
141 , m_exitCode(false)
142 , m_profile(false)
143 {
144 parseArguments(argc, argv);
145 }
146
147 bool m_interactive;
148 bool m_dump;
149 bool m_exitCode;
150 Vector<Script> m_scripts;
151 Vector<String> m_arguments;
152 bool m_profile;
153 String m_profilerOutput;
154
155 void parseArguments(int, char**);
156};
157
158static const char interactivePrompt[] = ">>> ";
159
160class StopWatch {
161public:
162 void start();
163 void stop();
164 long getElapsedMS(); // call stop() first
165
166private:
167 double m_startTime;
168 double m_stopTime;
169};
170
171void StopWatch::start()
172{
173 m_startTime = monotonicallyIncreasingTime();
174}
175
176void StopWatch::stop()
177{
178 m_stopTime = monotonicallyIncreasingTime();
179}
180
181long StopWatch::getElapsedMS()
182{
183 return static_cast<long>((m_stopTime - m_startTime) * 1000);
184}
185
186class GlobalObject : public JSGlobalObject {
187private:
188 GlobalObject(VM&, Structure*);
189
190public:
191 typedef JSGlobalObject Base;
192
193 static GlobalObject* create(VM& vm, Structure* structure, const Vector<String>& arguments)
194 {
195 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(vm.heap)) GlobalObject(vm, structure);
196 object->finishCreation(vm, arguments);
197 vm.heap.addFinalizer(object, destroy);
198 object->setGlobalThis(vm, JSProxy::create(vm, JSProxy::createStructure(vm, object, object->prototype()), object));
199 return object;
200 }
201
202 static const bool needsDestruction = false;
203
204 DECLARE_INFO;
205 static const GlobalObjectMethodTable s_globalObjectMethodTable;
206
207 static Structure* createStructure(VM& vm, JSValue prototype)
208 {
209 return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
210 }
211
212 static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return true; }
213
214protected:
215 void finishCreation(VM& vm, const Vector<String>& arguments)
216 {
217 Base::finishCreation(vm);
218
219 addFunction(vm, "debug", functionDebug, 1);
220 addFunction(vm, "describe", functionDescribe, 1);
221 addFunction(vm, "print", functionPrint, 1);
222 addFunction(vm, "quit", functionQuit, 0);
223 addFunction(vm, "gc", functionGC, 0);
224#ifndef NDEBUG
225 addFunction(vm, "dumpCallFrame", functionDumpCallFrame, 0);
226 addFunction(vm, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
227#endif
228 addFunction(vm, "version", functionVersion, 1);
229 addFunction(vm, "run", functionRun, 1);
230 addFunction(vm, "load", functionLoad, 1);
231 addFunction(vm, "checkSyntax", functionCheckSyntax, 1);
232 addFunction(vm, "jscStack", functionJSCStack, 1);
233 addFunction(vm, "readline", functionReadline, 0);
234 addFunction(vm, "preciseTime", functionPreciseTime, 0);
235#if ENABLE(SAMPLING_FLAGS)
236 addFunction(vm, "setSamplingFlags", functionSetSamplingFlags, 1);
237 addFunction(vm, "clearSamplingFlags", functionClearSamplingFlags, 1);
238#endif
239
240 JSArray* array = constructEmptyArray(globalExec(), 0);
241 for (size_t i = 0; i < arguments.size(); ++i)
242 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
243 putDirect(vm, Identifier(globalExec(), "arguments"), array);
244 }
245
246 void addFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
247 {
248 Identifier identifier(globalExec(), name);
249 putDirect(vm, identifier, JSFunction::create(globalExec(), this, arguments, identifier.string(), function));
250 }
251
252 void addConstructableFunction(VM& vm, const char* name, NativeFunction function, unsigned arguments)
253 {
254 Identifier identifier(globalExec(), name);
255 putDirect(vm, identifier, JSFunction::create(globalExec(), this, arguments, identifier.string(), function, NoIntrinsic, function));
256 }
257};
258
259COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
260
261const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
262const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, 0 };
263
264
265GlobalObject::GlobalObject(VM& vm, Structure* structure)
266 : JSGlobalObject(vm, structure, &s_globalObjectMethodTable)
267{
268}
269
270static inline String stringFromUTF(const char* utf8)
271{
272 // Find the the first non-ascii character, or nul.
273 const char* pos = utf8;
274 while (*pos > 0)
275 pos++;
276 size_t asciiLength = pos - utf8;
277
278 // Fast case - string is all ascii.
279 if (!*pos)
280 return String(utf8, asciiLength);
281
282 // Slow case - contains non-ascii characters, use fromUTF8WithLatin1Fallback.
283 ASSERT(*pos < 0);
284 ASSERT(strlen(utf8) == asciiLength + strlen(pos));
285 return String::fromUTF8WithLatin1Fallback(utf8, asciiLength + strlen(pos));
286}
287
288static inline SourceCode jscSource(const char* utf8, const String& filename)
289{
290 String str = stringFromUTF(utf8);
291 return makeSource(str, filename);
292}
293
294EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
295{
296 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
297 if (i)
298 putchar(' ');
299
300 printf("%s", exec->argument(i).toString(exec)->value(exec).utf8().data());
301 }
302
303 putchar('\n');
304 fflush(stdout);
305 return JSValue::encode(jsUndefined());
306}
307
308#ifndef NDEBUG
309EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
310{
311 if (!exec->callerFrame()->hasHostCallFrameFlag())
312 exec->vm().interpreter->dumpCallFrame(exec->callerFrame());
313 return JSValue::encode(jsUndefined());
314}
315#endif
316
317EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
318{
319 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
320 return JSValue::encode(jsUndefined());
321}
322
323EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
324{
325 fprintf(stderr, "--> %s\n", toCString(exec->argument(0)).data());
326 return JSValue::encode(jsUndefined());
327}
328
329class FunctionJSCStackFunctor {
330public:
331 FunctionJSCStackFunctor(StringBuilder& trace)
332 : m_trace(trace)
333 {
334 }
335
336 StackIterator::Status operator()(StackIterator& iter)
337 {
338 m_trace.append(String::format(" %zu %s\n", iter->index(), iter->toString().utf8().data()));
339 return StackIterator::Continue;
340 }
341
342private:
343 StringBuilder& m_trace;
344};
345
346EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
347{
348 StringBuilder trace;
349 trace.appendLiteral("--> Stack trace:\n");
350
351 FunctionJSCStackFunctor functor(trace);
352 StackIterator iter = exec->begin();
353 iter.iterate(functor);
354 fprintf(stderr, "%s", trace.toString().utf8().data());
355 return JSValue::encode(jsUndefined());
356}
357
358EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
359{
360 JSLockHolder lock(exec);
361 exec->heap()->collectAllGarbage();
362 return JSValue::encode(jsUndefined());
363}
364
365#ifndef NDEBUG
366EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
367{
368 JSLockHolder lock(exec);
369 exec->vm().releaseExecutableMemory();
370 return JSValue::encode(jsUndefined());
371}
372#endif
373
374EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
375{
376 // We need this function for compatibility with the Mozilla JS tests but for now
377 // we don't actually do any version-specific handling
378 return JSValue::encode(jsUndefined());
379}
380
381EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
382{
383 String fileName = exec->argument(0).toString(exec)->value(exec);
384 Vector<char> script;
385 if (!fillBufferWithContentsOfFile(fileName, script))
386 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
387
388 GlobalObject* globalObject = GlobalObject::create(exec->vm(), GlobalObject::createStructure(exec->vm(), jsNull()), Vector<String>());
389
390 JSValue exception;
391 StopWatch stopWatch;
392 stopWatch.start();
393 evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception);
394 stopWatch.stop();
395
396 if (!!exception) {
397 exec->vm().throwException(globalObject->globalExec(), exception);
398 return JSValue::encode(jsUndefined());
399 }
400
401 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
402}
403
404EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
405{
406 String fileName = exec->argument(0).toString(exec)->value(exec);
407 Vector<char> script;
408 if (!fillBufferWithContentsOfFile(fileName, script))
409 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
410
411 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
412
413 JSValue evaluationException;
414 JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
415 if (evaluationException)
416 exec->vm().throwException(exec, evaluationException);
417 return JSValue::encode(result);
418}
419
420EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
421{
422 String fileName = exec->argument(0).toString(exec)->value(exec);
423 Vector<char> script;
424 if (!fillBufferWithContentsOfFile(fileName, script))
425 return JSValue::encode(exec->vm().throwException(exec, createError(exec, "Could not open file.")));
426
427 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
428
429 StopWatch stopWatch;
430 stopWatch.start();
431
432 JSValue syntaxException;
433 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
434 stopWatch.stop();
435
436 if (!validSyntax)
437 exec->vm().throwException(exec, syntaxException);
438 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
439}
440
441#if ENABLE(SAMPLING_FLAGS)
442EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
443{
444 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
445 unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
446 if ((flag >= 1) && (flag <= 32))
447 SamplingFlags::setFlag(flag);
448 }
449 return JSValue::encode(jsNull());
450}
451
452EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
453{
454 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
455 unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
456 if ((flag >= 1) && (flag <= 32))
457 SamplingFlags::clearFlag(flag);
458 }
459 return JSValue::encode(jsNull());
460}
461#endif
462
463EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
464{
465 Vector<char, 256> line;
466 int c;
467 while ((c = getchar()) != EOF) {
468 // FIXME: Should we also break on \r?
469 if (c == '\n')
470 break;
471 line.append(c);
472 }
473 line.append('\0');
474 return JSValue::encode(jsString(exec, line.data()));
475}
476
477EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
478{
479 return JSValue::encode(jsNumber(currentTime()));
480}
481
482EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
483{
484 exit(EXIT_SUCCESS);
485
486#if COMPILER(MSVC) && OS(WINCE)
487 // Without this, Visual Studio will complain that this method does not return a value.
488 return JSValue::encode(jsUndefined());
489#endif
490}
491
492// Use SEH for Release builds only to get rid of the crash report dialog
493// (luckily the same tests fail in Release and Debug builds so far). Need to
494// be in a separate main function because the jscmain function requires object
495// unwinding.
496
497#if COMPILER(MSVC) && !COMPILER(INTEL) && !defined(_DEBUG) && !OS(WINCE)
498#define TRY __try {
499#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
500#else
501#define TRY
502#define EXCEPT(x)
503#endif
504
505int jscmain(int argc, char** argv);
506
507int main(int argc, char** argv)
508{
509#if PLATFORM(IOS)
510 // Enabled IEEE754 denormal support.
511 fenv_t env;
512 fegetenv( &env );
513 env.__fpscr &= ~0x01000000u;
514 fesetenv( &env );
515#endif
516
517#if OS(WINDOWS)
518#if !OS(WINCE)
519 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
520 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
521 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
522 ::SetErrorMode(0);
523#endif
524
525#if defined(_DEBUG)
526 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
527 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
528 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
529 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
530 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
531 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
532#endif
533
534 timeBeginPeriod(1);
535#endif
536
537#if PLATFORM(BLACKBERRY)
538 // Write all WTF logs to the system log
539 BlackBerry::Platform::setupApplicationLogging("jsc");
540#endif
541
542#if PLATFORM(QT)
543 QCoreApplication app(argc, argv);
544#endif
545
546#if PLATFORM(EFL)
547 ecore_init();
548#endif
549
550 // Initialize JSC before getting VM.
551#if ENABLE(SAMPLING_REGIONS)
552 WTF::initializeMainThread();
553#endif
554 JSC::initializeThreading();
555
556 // We can't use destructors in the following code because it uses Windows
557 // Structured Exception Handling
558 int res = 0;
559 TRY
560 res = jscmain(argc, argv);
561 EXCEPT(res = 3)
562 if (Options::logHeapStatisticsAtExit())
563 HeapStatistics::reportSuccess();
564
565#if PLATFORM(EFL)
566 ecore_shutdown();
567#endif
568
569 return res;
570}
571
572static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
573{
574 const char* script;
575 String fileName;
576 Vector<char> scriptBuffer;
577
578 if (dump)
579 JSC::Options::dumpGeneratedBytecodes() = true;
580
581 VM& vm = globalObject->vm();
582
583#if ENABLE(SAMPLING_FLAGS)
584 SamplingFlags::start();
585#endif
586
587 bool success = true;
588 for (size_t i = 0; i < scripts.size(); i++) {
589 if (scripts[i].isFile) {
590 fileName = scripts[i].argument;
591 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
592 return false; // fail early so we can catch missing files
593 script = scriptBuffer.data();
594 } else {
595 script = scripts[i].argument;
596 fileName = "[Command Line]";
597 }
598
599 vm.startSampling();
600
601 JSValue evaluationException;
602 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
603 success = success && !evaluationException;
604 if (dump && !evaluationException)
605 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
606 if (evaluationException) {
607 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
608 Identifier stackID(globalObject->globalExec(), "stack");
609 JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
610 if (!stackValue.isUndefinedOrNull())
611 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
612 }
613
614 vm.stopSampling();
615 globalObject->globalExec()->clearException();
616 }
617
618#if ENABLE(SAMPLING_FLAGS)
619 SamplingFlags::stop();
620#endif
621#if ENABLE(SAMPLING_REGIONS)
622 SamplingRegion::dump();
623#endif
624 vm.dumpSampleData(globalObject->globalExec());
625#if ENABLE(SAMPLING_COUNTERS)
626 AbstractSamplingCounter::dump();
627#endif
628#if ENABLE(REGEXP_TRACING)
629 vm.dumpRegExpTrace();
630#endif
631 return success;
632}
633
634#define RUNNING_FROM_XCODE 0
635
636static void runInteractive(GlobalObject* globalObject)
637{
638 String interpreterName("Interpreter");
639
640 bool shouldQuit = false;
641 while (!shouldQuit) {
642#if HAVE(READLINE) && !RUNNING_FROM_XCODE
643 ParserError error;
644 String source;
645 do {
646 error = ParserError();
647 char* line = readline(source.isEmpty() ? interactivePrompt : "... ");
648 shouldQuit = !line;
649 if (!line)
650 break;
651 source = source + line;
652 source = source + '\n';
653 checkSyntax(globalObject->vm(), makeSource(source, interpreterName), error);
654 if (!line[0])
655 break;
656 add_history(line);
657 } while (error.m_syntaxErrorType == ParserError::SyntaxErrorRecoverable);
658
659 if (error.m_type != ParserError::ErrorNone) {
660 printf("%s:%d\n", error.m_message.utf8().data(), error.m_line);
661 continue;
662 }
663
664
665 JSValue evaluationException;
666 JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException);
667#else
668 printf("%s", interactivePrompt);
669 Vector<char, 256> line;
670 int c;
671 while ((c = getchar()) != EOF) {
672 // FIXME: Should we also break on \r?
673 if (c == '\n')
674 break;
675 line.append(c);
676 }
677 if (line.isEmpty())
678 break;
679 line.append('\0');
680
681 JSValue evaluationException;
682 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
683#endif
684 if (evaluationException)
685 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
686 else
687 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
688
689 globalObject->globalExec()->clearException();
690 }
691 printf("\n");
692}
693
694static NO_RETURN void printUsageStatement(bool help = false)
695{
696 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
697 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
698 fprintf(stderr, " -e Evaluate argument as script code\n");
699 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
700 fprintf(stderr, " -h|--help Prints this help message\n");
701 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
702#if HAVE(SIGNAL_H)
703 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
704#endif
705 fprintf(stderr, " -p <file> Outputs profiling data to a file\n");
706 fprintf(stderr, " -x Output exit code before terminating\n");
707 fprintf(stderr, "\n");
708 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
709 fprintf(stderr, " --dumpOptions Dumps all JSC VM options before continuing\n");
710 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
711 fprintf(stderr, "\n");
712
713 exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
714}
715
716void CommandLine::parseArguments(int argc, char** argv)
717{
718 int i = 1;
719 bool needToDumpOptions = false;
720 bool needToExit = false;
721
722 for (; i < argc; ++i) {
723 const char* arg = argv[i];
724 if (!strcmp(arg, "-f")) {
725 if (++i == argc)
726 printUsageStatement();
727 m_scripts.append(Script(true, argv[i]));
728 continue;
729 }
730 if (!strcmp(arg, "-e")) {
731 if (++i == argc)
732 printUsageStatement();
733 m_scripts.append(Script(false, argv[i]));
734 continue;
735 }
736 if (!strcmp(arg, "-i")) {
737 m_interactive = true;
738 continue;
739 }
740 if (!strcmp(arg, "-d")) {
741 m_dump = true;
742 continue;
743 }
744 if (!strcmp(arg, "-p")) {
745 if (++i == argc)
746 printUsageStatement();
747 m_profile = true;
748 m_profilerOutput = argv[i];
749 continue;
750 }
751 if (!strcmp(arg, "-s")) {
752#if HAVE(SIGNAL_H)
753 signal(SIGILL, _exit);
754 signal(SIGFPE, _exit);
755 signal(SIGBUS, _exit);
756 signal(SIGSEGV, _exit);
757#endif
758 continue;
759 }
760 if (!strcmp(arg, "-x")) {
761 m_exitCode = true;
762 continue;
763 }
764 if (!strcmp(arg, "--")) {
765 ++i;
766 break;
767 }
768 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
769 printUsageStatement(true);
770
771 if (!strcmp(arg, "--options")) {
772 needToDumpOptions = true;
773 needToExit = true;
774 continue;
775 }
776 if (!strcmp(arg, "--dumpOptions")) {
777 needToDumpOptions = true;
778 continue;
779 }
780
781 // See if the -- option is a JSC VM option.
782 // NOTE: At this point, we know that the arg starts with "--". Skip it.
783 if (JSC::Options::setOption(&arg[2])) {
784 // The arg was recognized as a VM option and has been parsed.
785 continue; // Just continue with the next arg.
786 }
787
788 // This arg is not recognized by the VM nor by jsc. Pass it on to the
789 // script.
790 m_scripts.append(Script(true, argv[i]));
791 }
792
793 if (m_scripts.isEmpty())
794 m_interactive = true;
795
796 for (; i < argc; ++i)
797 m_arguments.append(argv[i]);
798
799 if (needToDumpOptions)
800 JSC::Options::dumpAllOptions(stderr);
801 if (needToExit)
802 exit(EXIT_SUCCESS);
803}
804
805int jscmain(int argc, char** argv)
806{
807 // Note that the options parsing can affect VM creation, and thus
808 // comes first.
809 CommandLine options(argc, argv);
810 VM* vm = VM::create(LargeHeap).leakRef();
811 APIEntryShim shim(vm);
812 int result;
813
814 if (options.m_profile && !vm->m_perBytecodeProfiler)
815 vm->m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*vm));
816
817 GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
818 bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump);
819 if (options.m_interactive && success)
820 runInteractive(globalObject);
821
822 result = success ? 0 : 3;
823
824 if (options.m_exitCode)
825 printf("jsc exiting %d\n", result);
826
827 if (options.m_profile) {
828 if (!vm->m_perBytecodeProfiler->save(options.m_profilerOutput.utf8().data()))
829 fprintf(stderr, "could not save profiler output.\n");
830 }
831
832 return result;
833}
834
835static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
836{
837 FILE* f = fopen(fileName.utf8().data(), "r");
838 if (!f) {
839 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
840 return false;
841 }
842
843 size_t bufferSize = 0;
844 size_t bufferCapacity = 1024;
845
846 buffer.resize(bufferCapacity);
847
848 while (!feof(f) && !ferror(f)) {
849 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
850 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
851 bufferCapacity *= 2;
852 buffer.resize(bufferCapacity);
853 }
854 }
855 fclose(f);
856 buffer[bufferSize] = '\0';
857
858 if (buffer[0] == '#' && buffer[1] == '!')
859 buffer[0] = buffer[1] = '/';
860
861 return true;
862}
Note: See TracBrowser for help on using the repository browser.