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

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

dumpCallFrame is broken in ToT
https://bugs.webkit.org/show_bug.cgi?id=91444

Reviewed by Gavin Barraclough.

Various changes have been made to the SF calling convention, but
dumpCallFrame has not been updated to reflect these changes.
That resulted in both bogus information, as well as numerous
assertions of sadness.

This patch makes dumpCallFrame actually work again and adds the
wonderful feature of telling you the name of the variable that a
register reflects, or what value it contains.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::nameForRegister):

A really innefficient mechanism for finding the name of a local register.
This should only ever be used by debug code so this should be okay.

  • bytecode/CodeBlock.h:

(CodeBlock):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::generate):

Debug builds no longer throw away a functions symbol table, this allows
us to actually perform a register# to name mapping

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::link):

We weren't propogating the bytecode offset here leading to assertions
in debug builds when dumping bytecode of DFG compiled code.

  • interpreter/Interpreter.cpp:

(JSC):
(JSC::Interpreter::dumpRegisters):

Rework to actually be correct.

(JSC::getCallerInfo):

Return the byteocde offset as well now, given we have to determine it
anyway.

(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::retrieveCallerFromVMCode):

  • interpreter/Interpreter.h:

(Interpreter):

  • jsc.cpp:

(GlobalObject::finishCreation):
(functionDumpCallFrame):

Give debug builds of JSC a method for calling dumpCallFrame so we can
inspect a callframe without requiring us to break in a debugger.

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