source: webkit/trunk/JavaScriptCore/kjs/testkjs.cpp@ 34428

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

2008-06-07 Cameron Zwarich <[email protected]>

Reviewed by Sam.

Bug 17547: JavaScriptCore print() differs from Spidermonkey Behavior
<https://bugs.webkit.org/show_bug.cgi?id=17547>

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