1 // -*- c-basic-offset: 2 -*-
3 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
4 * Copyright (C) 2004-2007 Apple Inc.
5 * Copyright (C) 2006 Bjoern Graf (bjoern.graf@gmail.com)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
26 #include "JSGlobalObject.h"
29 #include "collector.h"
30 #include "interpreter.h"
37 #include <wtf/Assertions.h>
38 #include <wtf/HashTraits.h>
56 static bool fillBufferWithContentsOfFile(const UString
& fileName
, Vector
<char>& buffer
);
63 long getElapsedMS(); // call stop() first
69 #elif PLATFORM(WIN_OS)
73 // Windows does not have timeval, disabling this class for now (bug 7399)
79 void StopWatch::start()
82 QDateTime t
= QDateTime::currentDateTime();
83 m_startTime
= t
.toTime_t() * 1000 + t
.time().msec();
84 #elif PLATFORM(WIN_OS)
85 m_startTime
= timeGetTime();
87 gettimeofday(&m_startTime
, 0);
91 void StopWatch::stop()
94 QDateTime t
= QDateTime::currentDateTime();
95 m_stopTime
= t
.toTime_t() * 1000 + t
.time().msec();
96 #elif PLATFORM(WIN_OS)
97 m_stopTime
= timeGetTime();
99 gettimeofday(&m_stopTime
, 0);
103 long StopWatch::getElapsedMS()
105 #if PLATFORM(WIN_OS) || PLATFORM(QT)
106 return m_stopTime
- m_startTime
;
109 timersub(&m_stopTime
, &m_startTime
, &elapsedTime
);
111 return elapsedTime
.tv_sec
* 1000 + lroundf(elapsedTime
.tv_usec
/ 1000.0f
);
115 class GlobalImp
: public JSGlobalObject
{
117 virtual UString
className() const { return "global"; }
119 COMPILE_ASSERT(!IsInteger
<GlobalImp
>::value
, WTF_IsInteger_GlobalImp_false
);
121 class TestFunctionImp
: public JSObject
{
123 enum TestFunctionType
{ Print
, Debug
, Quit
, GC
, Version
, Run
, Load
};
125 TestFunctionImp(TestFunctionType i
, int length
);
126 virtual bool implementsCall() const { return true; }
127 virtual JSValue
* callAsFunction(ExecState
* exec
, JSObject
* thisObj
, const List
&args
);
130 TestFunctionType m_type
;
133 TestFunctionImp::TestFunctionImp(TestFunctionType i
, int length
)
137 putDirect(Identifier("length"), length
, DontDelete
| ReadOnly
| DontEnum
);
140 JSValue
* TestFunctionImp::callAsFunction(ExecState
* exec
, JSObject
*, const List
&args
)
144 printf("%s\n", args
[0]->toString(exec
).UTF8String().c_str());
145 return jsUndefined();
147 fprintf(stderr
, "--> %s\n", args
[0]->toString(exec
).UTF8String().c_str());
148 return jsUndefined();
152 Collector::collect();
153 return jsUndefined();
156 // We need this function for compatibility with the Mozilla JS tests but for now
157 // we don't actually do any version-specific handling
158 return jsUndefined();
162 UString fileName
= args
[0]->toString(exec
);
164 if (!fillBufferWithContentsOfFile(fileName
, script
))
165 return throwError(exec
, GeneralError
, "Could not open file.");
168 Interpreter::evaluate(exec
->dynamicGlobalObject()->globalExec(), fileName
, 0, script
.data());
171 return jsNumber(stopWatch
.getElapsedMS());
175 UString fileName
= args
[0]->toString(exec
);
177 if (!fillBufferWithContentsOfFile(fileName
, script
))
178 return throwError(exec
, GeneralError
, "Could not open file.");
180 Interpreter::evaluate(exec
->dynamicGlobalObject()->globalExec(), fileName
, 0, script
.data());
182 return jsUndefined();
192 // Use SEH for Release builds only to get rid of the crash report dialog
193 // (luckily the same tests fail in Release and Debug builds so far). Need to
194 // be in a separate main function because the kjsmain function requires object
197 #if PLATFORM(WIN_OS) && !defined(_DEBUG)
199 #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
205 int kjsmain(int argc
, char** argv
);
207 int main(int argc
, char** argv
)
209 #if defined(_DEBUG) && PLATFORM(WIN_OS)
210 _CrtSetReportFile(_CRT_WARN
, _CRTDBG_FILE_STDERR
);
211 _CrtSetReportMode(_CRT_WARN
, _CRTDBG_MODE_FILE
);
212 _CrtSetReportFile(_CRT_ERROR
, _CRTDBG_FILE_STDERR
);
213 _CrtSetReportMode(_CRT_ERROR
, _CRTDBG_MODE_FILE
);
214 _CrtSetReportFile(_CRT_ASSERT
, _CRTDBG_FILE_STDERR
);
215 _CrtSetReportMode(_CRT_ASSERT
, _CRTDBG_MODE_FILE
);
220 res
= kjsmain(argc
, argv
);
225 static GlobalImp
* createGlobalObject()
227 GlobalImp
* global
= new GlobalImp
;
229 // add debug() function
230 global
->put(global
->globalExec(), "debug", new TestFunctionImp(TestFunctionImp::Debug
, 1));
231 // add "print" for compatibility with the mozilla js shell
232 global
->put(global
->globalExec(), "print", new TestFunctionImp(TestFunctionImp::Print
, 1));
233 // add "quit" for compatibility with the mozilla js shell
234 global
->put(global
->globalExec(), "quit", new TestFunctionImp(TestFunctionImp::Quit
, 0));
235 // add "gc" for compatibility with the mozilla js shell
236 global
->put(global
->globalExec(), "gc", new TestFunctionImp(TestFunctionImp::GC
, 0));
237 // add "version" for compatibility with the mozilla js shell
238 global
->put(global
->globalExec(), "version", new TestFunctionImp(TestFunctionImp::Version
, 1));
239 global
->put(global
->globalExec(), "run", new TestFunctionImp(TestFunctionImp::Run
, 1));
240 global
->put(global
->globalExec(), "load", new TestFunctionImp(TestFunctionImp::Load
, 1));
242 Interpreter::setShouldPrintExceptions(true);
246 static bool prettyPrintScript(const UString
& fileName
, const Vector
<char>& script
)
250 UString
scriptUString(script
.data());
251 RefPtr
<ProgramNode
> programNode
= parser().parse
<ProgramNode
>(fileName
, 0, scriptUString
.data(), scriptUString
.size(), 0, &errLine
, &errMsg
);
253 fprintf(stderr
, "%s:%d: %s.\n", fileName
.UTF8String().c_str(), errLine
, errMsg
.UTF8String().c_str());
257 printf("%s\n", programNode
->toString().UTF8String().c_str());
261 static bool runWithScripts(const Vector
<UString
>& fileNames
, bool prettyPrint
)
263 GlobalImp
* globalObject
= createGlobalObject();
268 for (size_t i
= 0; i
< fileNames
.size(); i
++) {
269 UString fileName
= fileNames
[i
];
271 if (!fillBufferWithContentsOfFile(fileName
, script
))
272 return false; // fail early so we can catch missing files
275 prettyPrintScript(fileName
, script
);
277 Completion completion
= Interpreter::evaluate(globalObject
->globalExec(), fileName
, 0, script
.data());
278 success
= success
&& completion
.complType() != Throw
;
284 static void parseArguments(int argc
, char** argv
, Vector
<UString
>& fileNames
, bool& prettyPrint
)
287 fprintf(stderr
, "Usage: testkjs file1 [file2...]\n");
291 for (int i
= 1; i
< argc
; i
++) {
292 const char* fileName
= argv
[i
];
293 if (strcmp(fileName
, "-f") == 0) // mozilla test driver script uses "-f" prefix for files
295 if (strcmp(fileName
, "-p") == 0) {
299 fileNames
.append(fileName
);
303 int kjsmain(int argc
, char** argv
)
307 bool prettyPrint
= false;
308 Vector
<UString
> fileNames
;
309 parseArguments(argc
, argv
, fileNames
, prettyPrint
);
311 bool success
= runWithScripts(fileNames
, prettyPrint
);
314 Collector::collect();
317 return success
? 0 : 3;
320 static bool fillBufferWithContentsOfFile(const UString
& fileName
, Vector
<char>& buffer
)
322 FILE* f
= fopen(fileName
.UTF8String().c_str(), "r");
324 fprintf(stderr
, "Could not open file: %s\n", fileName
.UTF8String().c_str());
328 size_t buffer_size
= 0;
329 size_t buffer_capacity
= 1024;
331 buffer
.resize(buffer_capacity
);
333 while (!feof(f
) && !ferror(f
)) {
334 buffer_size
+= fread(buffer
.data() + buffer_size
, 1, buffer_capacity
- buffer_size
, f
);
335 if (buffer_size
== buffer_capacity
) { // guarantees space for trailing '\0'
336 buffer_capacity
*= 2;
337 buffer
.resize(buffer_capacity
);
341 buffer
[buffer_size
] = '\0';