source: webkit/trunk/JavaScriptCore/jsc.cpp@ 38205

Last change on this file since 38205 was 38162, checked in by [email protected], 17 years ago

2008-11-06 Cameron Zwarich <[email protected]>

Rubber-stamped by Sam Weinig.

Move kjs/Shell.cpp to the top level of the JavaScriptCore directory and
rename it to jsc.cpp to reflect the name of the binary compiled from it.

  • GNUmakefile.am:
  • JavaScriptCore.vcproj/jsc/jsc.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • jsc.cpp: Copied from kjs/Shell.cpp.
  • jsc.pro:
  • jscore.bkl:
  • kjs/Shell.cpp: Removed.
  • Property svn:eol-style set to native
File size: 15.9 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 "Completion.h"
26#include "CodeGenerator.h"
27#include "InitializeThreading.h"
28#include "Interpreter.h"
29#include "JSArray.h"
30#include "JSLock.h"
31#include "PrototypeFunction.h"
32#include "SamplingTool.h"
33#include <math.h>
34#include <stdio.h>
35#include <string.h>
36
37#if !PLATFORM(WIN_OS)
38#include <unistd.h>
39#endif
40
41#if HAVE(READLINE)
42#include <readline/history.h>
43#include <readline/readline.h>
44#endif
45
46#if HAVE(SYS_TIME_H)
47#include <sys/time.h>
48#endif
49
50#if PLATFORM(UNIX)
51#include <signal.h>
52#endif
53
54#if COMPILER(MSVC)
55#include <crtdbg.h>
56#include <windows.h>
57#endif
58
59#if PLATFORM(QT)
60#include <QCoreApplication>
61#include <QDateTime>
62#endif
63
64using namespace JSC;
65using namespace WTF;
66
67static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer);
68
69static JSValue* functionPrint(ExecState*, JSObject*, JSValue*, const ArgList&);
70static JSValue* functionDebug(ExecState*, JSObject*, JSValue*, const ArgList&);
71static JSValue* functionGC(ExecState*, JSObject*, JSValue*, const ArgList&);
72static JSValue* functionVersion(ExecState*, JSObject*, JSValue*, const ArgList&);
73static JSValue* functionRun(ExecState*, JSObject*, JSValue*, const ArgList&);
74static JSValue* functionLoad(ExecState*, JSObject*, JSValue*, const ArgList&);
75static JSValue* functionReadline(ExecState*, JSObject*, JSValue*, const ArgList&);
76static JSValue* functionQuit(ExecState*, JSObject*, JSValue*, const ArgList&);
77
78struct Options {
79 Options()
80 : interactive(false)
81 , prettyPrint(false)
82 , dump(false)
83 {
84 }
85
86 bool interactive;
87 bool prettyPrint;
88 bool dump;
89 Vector<UString> fileNames;
90 Vector<UString> arguments;
91};
92
93static const char interactivePrompt[] = "> ";
94static const UString interpreterName("Interpreter");
95
96class StopWatch {
97public:
98 void start();
99 void stop();
100 long getElapsedMS(); // call stop() first
101
102private:
103#if PLATFORM(QT)
104 uint m_startTime;
105 uint m_stopTime;
106#elif PLATFORM(WIN_OS)
107 DWORD m_startTime;
108 DWORD m_stopTime;
109#else
110 // Windows does not have timeval, disabling this class for now (bug 7399)
111 timeval m_startTime;
112 timeval m_stopTime;
113#endif
114};
115
116void StopWatch::start()
117{
118#if PLATFORM(QT)
119 QDateTime t = QDateTime::currentDateTime();
120 m_startTime = t.toTime_t() * 1000 + t.time().msec();
121#elif PLATFORM(WIN_OS)
122 m_startTime = timeGetTime();
123#else
124 gettimeofday(&m_startTime, 0);
125#endif
126}
127
128void StopWatch::stop()
129{
130#if PLATFORM(QT)
131 QDateTime t = QDateTime::currentDateTime();
132 m_stopTime = t.toTime_t() * 1000 + t.time().msec();
133#elif PLATFORM(WIN_OS)
134 m_stopTime = timeGetTime();
135#else
136 gettimeofday(&m_stopTime, 0);
137#endif
138}
139
140long StopWatch::getElapsedMS()
141{
142#if PLATFORM(WIN_OS) || PLATFORM(QT)
143 return m_stopTime - m_startTime;
144#else
145 timeval elapsedTime;
146 timersub(&m_stopTime, &m_startTime, &elapsedTime);
147
148 return elapsedTime.tv_sec * 1000 + lroundf(elapsedTime.tv_usec / 1000.0f);
149#endif
150}
151
152class GlobalObject : public JSGlobalObject {
153public:
154 GlobalObject(const Vector<UString>& arguments);
155 virtual UString className() const { return "global"; }
156};
157COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
158ASSERT_CLASS_FITS_IN_CELL(GlobalObject);
159
160GlobalObject::GlobalObject(const Vector<UString>& arguments)
161 : JSGlobalObject()
162{
163 putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "debug"), functionDebug));
164 putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "print"), functionPrint));
165 putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "quit"), functionQuit));
166 putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "gc"), functionGC));
167 putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "version"), functionVersion));
168 putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "run"), functionRun));
169 putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "load"), functionLoad));
170 putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "readline"), functionReadline));
171
172 JSObject* array = constructEmptyArray(globalExec());
173 for (size_t i = 0; i < arguments.size(); ++i)
174 array->put(globalExec(), i, jsString(globalExec(), arguments[i]));
175 putDirect(Identifier(globalExec(), "arguments"), array);
176}
177
178JSValue* functionPrint(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
179{
180 for (unsigned i = 0; i < args.size(); ++i) {
181 if (i != 0)
182 putchar(' ');
183
184 printf("%s", args.at(exec, i)->toString(exec).UTF8String().c_str());
185 }
186
187 putchar('\n');
188 fflush(stdout);
189 return jsUndefined();
190}
191
192JSValue* functionDebug(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
193{
194 fprintf(stderr, "--> %s\n", args.at(exec, 0)->toString(exec).UTF8String().c_str());
195 return jsUndefined();
196}
197
198JSValue* functionGC(ExecState* exec, JSObject*, JSValue*, const ArgList&)
199{
200 JSLock lock(false);
201 exec->heap()->collect();
202 return jsUndefined();
203}
204
205JSValue* functionVersion(ExecState*, JSObject*, JSValue*, const ArgList&)
206{
207 // We need this function for compatibility with the Mozilla JS tests but for now
208 // we don't actually do any version-specific handling
209 return jsUndefined();
210}
211
212JSValue* functionRun(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
213{
214 StopWatch stopWatch;
215 UString fileName = args.at(exec, 0)->toString(exec);
216 Vector<char> script;
217 if (!fillBufferWithContentsOfFile(fileName, script))
218 return throwError(exec, GeneralError, "Could not open file.");
219
220 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
221
222 stopWatch.start();
223 Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
224 stopWatch.stop();
225
226 return jsNumber(globalObject->globalExec(), stopWatch.getElapsedMS());
227}
228
229JSValue* functionLoad(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
230{
231 UString fileName = args.at(exec, 0)->toString(exec);
232 Vector<char> script;
233 if (!fillBufferWithContentsOfFile(fileName, script))
234 return throwError(exec, GeneralError, "Could not open file.");
235
236 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
237 Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
238
239 return jsUndefined();
240}
241
242JSValue* functionReadline(ExecState* exec, JSObject*, JSValue*, const ArgList&)
243{
244 Vector<char, 256> line;
245 int c;
246 while ((c = getchar()) != EOF) {
247 // FIXME: Should we also break on \r?
248 if (c == '\n')
249 break;
250 line.append(c);
251 }
252 line.append('\0');
253 return jsString(exec, line.data());
254}
255
256JSValue* functionQuit(ExecState*, JSObject*, JSValue*, const ArgList&)
257{
258 exit(0);
259#if !COMPILER(MSVC)
260 // MSVC knows that exit(0) never returns, so it flags this return statement as unreachable.
261 return jsUndefined();
262#endif
263}
264
265// Use SEH for Release builds only to get rid of the crash report dialog
266// (luckily the same tests fail in Release and Debug builds so far). Need to
267// be in a separate main function because the jscmain function requires object
268// unwinding.
269
270#if COMPILER(MSVC) && !defined(_DEBUG)
271#define TRY __try {
272#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
273#else
274#define TRY
275#define EXCEPT(x)
276#endif
277
278int jscmain(int argc, char** argv, JSGlobalData*);
279
280int main(int argc, char** argv)
281{
282#if defined(_DEBUG) && PLATFORM(WIN_OS)
283 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
284 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
285 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
286 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
287 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
288 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
289#endif
290
291#if PLATFORM(QT)
292 QCoreApplication app(argc, argv);
293#endif
294
295 int res = 0;
296 TRY
297 res = jscmain(argc, argv, JSGlobalData::create().releaseRef());
298 EXCEPT(res = 3)
299 return res;
300}
301
302static bool prettyPrintScript(ExecState* exec, const UString& fileName, const Vector<char>& script)
303{
304 int errLine = 0;
305 UString errMsg;
306 RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), makeSource(script.data(), fileName), &errLine, &errMsg);
307 if (!programNode) {
308 fprintf(stderr, "%s:%d: %s.\n", fileName.UTF8String().c_str(), errLine, errMsg.UTF8String().c_str());
309 return false;
310 }
311
312 printf("%s\n", programNode->toString().UTF8String().c_str());
313 return true;
314}
315
316static bool runWithScripts(GlobalObject* globalObject, const Vector<UString>& fileNames, bool prettyPrint, bool dump)
317{
318 Vector<char> script;
319
320 if (dump)
321 CodeGenerator::setDumpsGeneratedCode(true);
322
323#if ENABLE(OPCODE_SAMPLING)
324 Machine* machine = globalObject->globalData()->machine;
325 machine->setSampler(new SamplingTool(machine));
326#endif
327
328 bool success = true;
329 for (size_t i = 0; i < fileNames.size(); i++) {
330 UString fileName = fileNames[i];
331
332 if (!fillBufferWithContentsOfFile(fileName, script))
333 return false; // fail early so we can catch missing files
334
335 if (prettyPrint)
336 prettyPrintScript(globalObject->globalExec(), fileName, script);
337 else {
338#if ENABLE(OPCODE_SAMPLING)
339 machine->sampler()->start();
340#endif
341 Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
342 success = success && completion.complType() != Throw;
343 if (dump) {
344 if (completion.complType() == Throw)
345 printf("Exception: %s\n", completion.value()->toString(globalObject->globalExec()).ascii());
346 else
347 printf("End: %s\n", completion.value()->toString(globalObject->globalExec()).ascii());
348 }
349
350 globalObject->globalExec()->clearException();
351
352#if ENABLE(OPCODE_SAMPLING)
353 machine->sampler()->stop();
354#endif
355 }
356 }
357
358#if ENABLE(OPCODE_SAMPLING)
359 machine->sampler()->dump(globalObject->globalExec());
360 delete machine->sampler();
361#endif
362 return success;
363}
364
365static void runInteractive(GlobalObject* globalObject)
366{
367 while (true) {
368#if HAVE(READLINE)
369 char* line = readline(interactivePrompt);
370 if (!line)
371 break;
372 if (line[0])
373 add_history(line);
374 Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(line, interpreterName));
375 free(line);
376#else
377 puts(interactivePrompt);
378 Vector<char, 256> line;
379 int c;
380 while ((c = getchar()) != EOF) {
381 // FIXME: Should we also break on \r?
382 if (c == '\n')
383 break;
384 line.append(c);
385 }
386 line.append('\0');
387 Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(line.data(), interpreterName));
388#endif
389 if (completion.complType() == Throw)
390 printf("Exception: %s\n", completion.value()->toString(globalObject->globalExec()).ascii());
391 else
392 printf("%s\n", completion.value()->toString(globalObject->globalExec()).UTF8String().c_str());
393
394 globalObject->globalExec()->clearException();
395 }
396 printf("\n");
397}
398
399static void printUsageStatement()
400{
401 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
402 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
403 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
404 fprintf(stderr, " -h|--help Prints this help message\n");
405 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
406 fprintf(stderr, " -p Prints formatted source code\n");
407 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
408 exit(-1);
409}
410
411static void parseArguments(int argc, char** argv, Options& options)
412{
413 int i = 1;
414 for (; i < argc; ++i) {
415 const char* arg = argv[i];
416 if (strcmp(arg, "-f") == 0) {
417 if (++i == argc)
418 printUsageStatement();
419 options.fileNames.append(argv[i]);
420 continue;
421 }
422 if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
423 printUsageStatement();
424 }
425 if (strcmp(arg, "-i") == 0) {
426 options.interactive = true;
427 continue;
428 }
429 if (strcmp(arg, "-p") == 0) {
430 options.prettyPrint = true;
431 continue;
432 }
433 if (strcmp(arg, "-d") == 0) {
434 options.dump = true;
435 continue;
436 }
437 if (strcmp(arg, "-s") == 0) {
438#if PLATFORM(UNIX)
439 signal(SIGILL, _exit);
440 signal(SIGFPE, _exit);
441 signal(SIGBUS, _exit);
442 signal(SIGSEGV, _exit);
443#endif
444 continue;
445 }
446 if (strcmp(arg, "--") == 0) {
447 ++i;
448 break;
449 }
450 options.fileNames.append(argv[i]);
451 }
452
453 if (options.fileNames.isEmpty())
454 options.interactive = true;
455
456 for (; i < argc; ++i)
457 options.arguments.append(argv[i]);
458}
459
460int jscmain(int argc, char** argv, JSGlobalData* globalData)
461{
462 JSC::initializeThreading();
463
464 JSLock lock(false);
465
466 Options options;
467 parseArguments(argc, argv, options);
468
469 GlobalObject* globalObject = new (globalData) GlobalObject(options.arguments);
470 bool success = runWithScripts(globalObject, options.fileNames, options.prettyPrint, options.dump);
471 if (options.interactive && success)
472 runInteractive(globalObject);
473
474 return success ? 0 : 3;
475}
476
477static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer)
478{
479 FILE* f = fopen(fileName.UTF8String().c_str(), "r");
480 if (!f) {
481 fprintf(stderr, "Could not open file: %s\n", fileName.UTF8String().c_str());
482 return false;
483 }
484
485 size_t buffer_size = 0;
486 size_t buffer_capacity = 1024;
487
488 buffer.resize(buffer_capacity);
489
490 while (!feof(f) && !ferror(f)) {
491 buffer_size += fread(buffer.data() + buffer_size, 1, buffer_capacity - buffer_size, f);
492 if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
493 buffer_capacity *= 2;
494 buffer.resize(buffer_capacity);
495 }
496 }
497 fclose(f);
498 buffer[buffer_size] = '\0';
499
500 return true;
501}
Note: See TracBrowser for help on using the repository browser.