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

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

Use one object instead of two for closures, eliminating ScopeChainNode
https://bugs.webkit.org/show_bug.cgi?id=95501

Reviewed by Filip Pizlo.

../JavaScriptCore:

This patch removes ScopeChainNode, and moves all the data and related
functions that used to be in ScopeChainNode into JSScope.

Most of this patch is mechanical changes to use a JSScope* where we used
to use a ScopeChainNode*. I've only specifically commented about items
that were non-mechanical.

  • runtime/Completion.cpp:

(JSC::evaluate):

  • runtime/Completion.h: Don't require an explicit scope chain argument

when evaluating code. Clients never wanted anything other than the
global scope, and other arbitrary scopes probably wouldn't work
correctly, anyway.

  • runtime/JSScope.cpp:
  • runtime/JSScope.h:

(JSC::JSScope::JSScope): JSScope now requires the data we used to pass to
ScopeChainNode, so it can link itself into the scope chain correctly.

  • runtime/JSWithScope.h:

(JSC::JSWithScope::create):
(JSC::JSWithScope::JSWithScope): JSWithScope gets an extra constructor
for specifically supplying your own scope chain. The DOM needs this
interface for setting up the scope chain for certain event handlers.
Other clients always just push the JSWithScope to the head of the current
scope chain.

../WebCore:

Mechanical changes to update for JSC interface changes.

../WebKit/mac:

Mechanical change to update for JSC interface change.

../WebKit/qt:

Mechanical change to update for JSC interface change.

  • Api/qwebelement.cpp:

(QWebElement::evaluateJavaScript):

../WebKit2:

Mechanical changes to update for JSC interface change.

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