source: webkit/trunk/JavaScriptCore/kjs/Shell.cpp@ 34852

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

2008-06-27 Sam Weinig <[email protected]>

Rubber-stamped by Oliver Hunt.

Splits ArrayConstructor out of ArrayPrototype.h/cpp
Splits BooleanConstructor and BooleanPrototype out of BooleanObject.h/cpp

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