jsc.cpp 28 KB

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