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

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

Removed Blackberry #ifdefs and platform code from JavaScriptCore
https://bugs.webkit.org/show_bug.cgi?id=126757

Reviewed by Sam Weinig.

  • PlatformBlackBerry.cmake: Removed.
  • heap/HeapTimer.cpp:
  • heap/HeapTimer.h:
  • heap/IncrementalSweeper.cpp:
  • heap/IncrementalSweeper.h:
  • jsc.cpp:

(main):

  • runtime/GCActivityCallbackBlackBerry.cpp: Removed.
  • runtime/MemoryStatistics.cpp:

(JSC::globalMemoryStatistics):

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