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

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

2009-09-24 Yong Li <[email protected]>

Reviewed by Adam Barth.

Replace platform-dependent code with WTF::currentTime()
https://bugs.webkit.org/show_bug.cgi?id=29148

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