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

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

[EFL] Implement GCActivityCallback
https://bugs.webkit.org/show_bug.cgi?id=95923

Patch by Hojong Han <[email protected]> on 2013-06-03
Reviewed by Geoffrey Garen.

Implements the activity triggered garbage collector.
Additional GCs can be triggered by platfrom timer.
It has sort of compaction effect not to make JSC heap grow fast
so that memory usage becomes lower than usual.

  • PlatformEfl.cmake: Added.
  • heap/HeapTimer.cpp:

(JSC):
(JSC::HeapTimer::HeapTimer):
(JSC::HeapTimer::~HeapTimer):
(JSC::HeapTimer::add):
(JSC::HeapTimer::stop):
(JSC::HeapTimer::timerEvent):

  • heap/HeapTimer.h:

(HeapTimer):

  • jsc.cpp:

(main):

  • runtime/GCActivityCallback.cpp:

(JSC):
(JSC::DefaultGCActivityCallback::DefaultGCActivityCallback):
(JSC::DefaultGCActivityCallback::scheduleTimer):
(JSC::DefaultGCActivityCallback::cancelTimer):
(JSC::DefaultGCActivityCallback::didAllocate):

  • runtime/GCActivityCallback.h:

(GCActivityCallback):
(JSC::GCActivityCallback::GCActivityCallback):
(DefaultGCActivityCallback):

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