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

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

Pass VM instead of ExecState to JSFunction constructors.
<https://webkit.org/b/122014>

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

JSFunction doesn't need the ExecState for anything during its
construction, so reduce the amount of loads by just passing the
VM around instead.

Factored out putDirectNonIndexAccessor() from the existing
putDirectAccessor() to avoid snowballing the patch (and because
it's kinda neat to avoid the extra branch.)

JSC release binary size -= 9680 bytes.

Source/WebCore:

Updated for new JSFunction::create() signature.

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