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

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

Tidy up codeblock sampler
https://bugs.webkit.org/show_bug.cgi?id=29836

Reviewed by Gavin Barraclough.

Some rather simple refactoring of codeblock sampler so that
it's easier for us to use it to find problems in non-jsc
environments

  • Property svn:eol-style set to native
File size: 18.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 "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 JSGlobalData* globalData = globalObject->globalData();
364
365#if ENABLE(SAMPLING_FLAGS)
366 SamplingFlags::start();
367#endif
368
369 bool success = true;
370 for (size_t i = 0; i < scripts.size(); i++) {
371 if (scripts[i].isFile) {
372 fileName = scripts[i].argument;
373 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
374 return false; // fail early so we can catch missing files
375 script = scriptBuffer.data();
376 } else {
377 script = scripts[i].argument;
378 fileName = "[Command Line]";
379 }
380
381 globalData->startSampling();
382
383 Completion completion = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script, fileName));
384 success = success && completion.complType() != Throw;
385 if (dump) {
386 if (completion.complType() == Throw)
387 printf("Exception: %s\n", completion.value().toString(globalObject->globalExec()).ascii());
388 else
389 printf("End: %s\n", completion.value().toString(globalObject->globalExec()).ascii());
390 }
391
392 globalData->stopSampling();
393 globalObject->globalExec()->clearException();
394 }
395
396#if ENABLE(SAMPLING_FLAGS)
397 SamplingFlags::stop();
398#endif
399 globalData->dumpSampleData(globalObject->globalExec());
400#if ENABLE(SAMPLING_COUNTERS)
401 AbstractSamplingCounter::dump();
402#endif
403 return success;
404}
405
406#define RUNNING_FROM_XCODE 0
407
408static void runInteractive(GlobalObject* globalObject)
409{
410 while (true) {
411#if HAVE(READLINE) && !RUNNING_FROM_XCODE
412 char* line = readline(interactivePrompt);
413 if (!line)
414 break;
415 if (line[0])
416 add_history(line);
417 Completion completion = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(line, interpreterName));
418 free(line);
419#else
420 printf("%s", interactivePrompt);
421 Vector<char, 256> line;
422 int c;
423 while ((c = getchar()) != EOF) {
424 // FIXME: Should we also break on \r?
425 if (c == '\n')
426 break;
427 line.append(c);
428 }
429 if (line.isEmpty())
430 break;
431 line.append('\0');
432 Completion completion = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(line.data(), interpreterName));
433#endif
434 if (completion.complType() == Throw)
435 printf("Exception: %s\n", completion.value().toString(globalObject->globalExec()).ascii());
436 else
437 printf("%s\n", completion.value().toString(globalObject->globalExec()).UTF8String().c_str());
438
439 globalObject->globalExec()->clearException();
440 }
441 printf("\n");
442}
443
444static NO_RETURN void printUsageStatement(JSGlobalData* globalData, bool help = false)
445{
446 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
447 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
448 fprintf(stderr, " -e Evaluate argument as script code\n");
449 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
450 fprintf(stderr, " -h|--help Prints this help message\n");
451 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
452#if HAVE(SIGNAL_H)
453 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
454#endif
455
456 cleanupGlobalData(globalData);
457 exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
458}
459
460static void parseArguments(int argc, char** argv, Options& options, JSGlobalData* globalData)
461{
462 int i = 1;
463 for (; i < argc; ++i) {
464 const char* arg = argv[i];
465 if (strcmp(arg, "-f") == 0) {
466 if (++i == argc)
467 printUsageStatement(globalData);
468 options.scripts.append(Script(true, argv[i]));
469 continue;
470 }
471 if (strcmp(arg, "-e") == 0) {
472 if (++i == argc)
473 printUsageStatement(globalData);
474 options.scripts.append(Script(false, argv[i]));
475 continue;
476 }
477 if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
478 printUsageStatement(globalData, true);
479 }
480 if (strcmp(arg, "-i") == 0) {
481 options.interactive = true;
482 continue;
483 }
484 if (strcmp(arg, "-d") == 0) {
485 options.dump = true;
486 continue;
487 }
488 if (strcmp(arg, "-s") == 0) {
489#if HAVE(SIGNAL_H)
490 signal(SIGILL, _exit);
491 signal(SIGFPE, _exit);
492 signal(SIGBUS, _exit);
493 signal(SIGSEGV, _exit);
494#endif
495 continue;
496 }
497 if (strcmp(arg, "--") == 0) {
498 ++i;
499 break;
500 }
501 options.scripts.append(Script(true, argv[i]));
502 }
503
504 if (options.scripts.isEmpty())
505 options.interactive = true;
506
507 for (; i < argc; ++i)
508 options.arguments.append(argv[i]);
509}
510
511int jscmain(int argc, char** argv, JSGlobalData* globalData)
512{
513 JSLock lock(SilenceAssertionsOnly);
514
515 Options options;
516 parseArguments(argc, argv, options, globalData);
517
518 GlobalObject* globalObject = new (globalData) GlobalObject(options.arguments);
519 bool success = runWithScripts(globalObject, options.scripts, options.dump);
520 if (options.interactive && success)
521 runInteractive(globalObject);
522
523 return success ? 0 : 3;
524}
525
526static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer)
527{
528 FILE* f = fopen(fileName.UTF8String().c_str(), "r");
529 if (!f) {
530 fprintf(stderr, "Could not open file: %s\n", fileName.UTF8String().c_str());
531 return false;
532 }
533
534 size_t buffer_size = 0;
535 size_t buffer_capacity = 1024;
536
537 buffer.resize(buffer_capacity);
538
539 while (!feof(f) && !ferror(f)) {
540 buffer_size += fread(buffer.data() + buffer_size, 1, buffer_capacity - buffer_size, f);
541 if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
542 buffer_capacity *= 2;
543 buffer.resize(buffer_capacity);
544 }
545 }
546 fclose(f);
547 buffer[buffer_size] = '\0';
548
549 return true;
550}
Note: See TracBrowser for help on using the repository browser.