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

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

Use timeBeginPeriod to enable timing resolution greater than 16ms in command line jsc for Windows.
Allows more accurate reporting of benchmark times via command line jsc.exe. Doesn't affect WebKit's use of JavaScriptCore.


Reviewed by Adam Roben.

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