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

Last change on this file since 38286 was 38249, checked in by Darin Adler, 17 years ago

2008-11-09 Darin Adler <Darin Adler>

Reviewed by Tim Hatcher.

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