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

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

JavaScriptCore:

2008-07-05 Sam Weinig <[email protected]>

Rubber-stamped by Cameron Zwarich.

Split Arguments, IndexToNameMap, PrototypeFunction, GlobalEvalFunction and
the functions on the global object out of JSFunction.h/cpp.

  • GNUmakefile.am:
  • JavaScriptCore.pri:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • JavaScriptCoreSources.bkl:
  • VM/Machine.cpp:
  • kjs/AllInOneFile.cpp:
  • kjs/Arguments.cpp: Copied from JavaScriptCore/kjs/JSFunction.cpp.
  • kjs/Arguments.h: Copied from JavaScriptCore/kjs/JSFunction.h.
  • kjs/GlobalEvalFunction.cpp: Copied from JavaScriptCore/kjs/JSFunction.cpp.
  • kjs/GlobalEvalFunction.h: Copied from JavaScriptCore/kjs/JSFunction.h.
  • kjs/IndexToNameMap.cpp: Copied from JavaScriptCore/kjs/JSFunction.cpp.
  • kjs/IndexToNameMap.h: Copied from JavaScriptCore/kjs/JSFunction.h.
  • kjs/JSActivation.cpp:
  • kjs/JSFunction.cpp:
  • kjs/JSFunction.h:
  • kjs/JSGlobalObject.cpp:
  • kjs/JSGlobalObjectFunctions.cpp: Copied from JavaScriptCore/kjs/JSFunction.cpp.
  • kjs/JSGlobalObjectFunctions.h: Copied from JavaScriptCore/kjs/JSFunction.h. The functions on the global object should be in JSGlobalObject.cpp, but putting them there was a 0.5% regression.
  • kjs/PrototypeFunction.cpp: Copied from JavaScriptCore/kjs/JSFunction.cpp.
  • kjs/PrototypeFunction.h: Copied from JavaScriptCore/kjs/JSFunction.h.
  • kjs/Shell.cpp:
  • kjs/lexer.cpp:
  • kjs/ustring.cpp:

WebCore:

2008-07-05 Sam Weinig <[email protected]>

Rubber-stamped by Cameron Zwarich.

Split Arguments, IndexToNameMap, PrototypeFunction, GlobalEvalFunction and
the functions on the global object out of JSFunction.h/cpp.

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