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 "SourceCode.h" 
  30 #include "collector.h" 
  31 #include "interpreter.h" 
  38 #include <wtf/Assertions.h> 
  39 #include <wtf/HashTraits.h> 
  57 static bool fillBufferWithContentsOfFile(const UString
& fileName
, Vector
<char>& buffer
); 
  64     long getElapsedMS(); // call stop() first 
  70 #elif PLATFORM(WIN_OS) 
  74     // Windows does not have timeval, disabling this class for now (bug 7399) 
  80 void StopWatch::start() 
  83     QDateTime t 
= QDateTime::currentDateTime(); 
  84     m_startTime 
= t
.toTime_t() * 1000 + t
.time().msec(); 
  85 #elif PLATFORM(WIN_OS) 
  86     m_startTime 
= timeGetTime(); 
  88     gettimeofday(&m_startTime
, 0); 
  92 void StopWatch::stop() 
  95     QDateTime t 
= QDateTime::currentDateTime(); 
  96     m_stopTime 
= t
.toTime_t() * 1000 + t
.time().msec(); 
  97 #elif PLATFORM(WIN_OS) 
  98     m_stopTime 
= timeGetTime(); 
 100     gettimeofday(&m_stopTime
, 0); 
 104 long StopWatch::getElapsedMS() 
 106 #if PLATFORM(WIN_OS) || PLATFORM(QT) 
 107     return m_stopTime 
- m_startTime
; 
 110     timersub(&m_stopTime
, &m_startTime
, &elapsedTime
); 
 112     return elapsedTime
.tv_sec 
* 1000 + lroundf(elapsedTime
.tv_usec 
/ 1000.0f
); 
 116 class GlobalImp 
: public JSGlobalObject 
{ 
 118   virtual UString 
className() const { return "global"; } 
 120 COMPILE_ASSERT(!IsInteger
<GlobalImp
>::value
, WTF_IsInteger_GlobalImp_false
); 
 122 class TestFunctionImp 
: public JSObject 
{ 
 124   enum TestFunctionType 
{ Print
, Debug
, Quit
, GC
, Version
, Run
, Load 
}; 
 126   TestFunctionImp(TestFunctionType i
, int length
); 
 127   virtual bool implementsCall() const { return true; } 
 128   virtual JSValue
* callAsFunction(ExecState
* exec
, JSObject
* thisObj
, const List 
&args
); 
 131   TestFunctionType m_type
; 
 134 TestFunctionImp::TestFunctionImp(TestFunctionType i
, int length
) 
 138   putDirect(Identifier("length"), length
, DontDelete 
| ReadOnly 
| DontEnum
); 
 141 JSValue
* TestFunctionImp::callAsFunction(ExecState
* exec
, JSObject
*, const List 
&args
) 
 145       printf("%s\n", args
[0]->toString(exec
).UTF8String().c_str()); 
 146       return jsUndefined(); 
 148       fprintf(stderr
, "--> %s\n", args
[0]->toString(exec
).UTF8String().c_str()); 
 149       return jsUndefined(); 
 153       Collector::collect(); 
 154       return jsUndefined(); 
 157       // We need this function for compatibility with the Mozilla JS tests but for now 
 158       // we don't actually do any version-specific handling 
 159       return jsUndefined(); 
 163       UString fileName 
= args
[0]->toString(exec
); 
 165       if (!fillBufferWithContentsOfFile(fileName
, script
)) 
 166         return throwError(exec
, GeneralError
, "Could not open file."); 
 170       Interpreter::evaluate(exec
->dynamicGlobalObject()->globalExec(), makeSource(script
.data(), fileName
)); 
 173       return jsNumber(stopWatch
.getElapsedMS()); 
 177       UString fileName 
= args
[0]->toString(exec
); 
 179       if (!fillBufferWithContentsOfFile(fileName
, script
)) 
 180         return throwError(exec
, GeneralError
, "Could not open file."); 
 182       Interpreter::evaluate(exec
->dynamicGlobalObject()->globalExec(), makeSource(script
.data(), fileName
)); 
 184       return jsUndefined(); 
 194 // Use SEH for Release builds only to get rid of the crash report dialog 
 195 // (luckily the same tests fail in Release and Debug builds so far). Need to 
 196 // be in a separate main function because the kjsmain function requires object 
 199 #if PLATFORM(WIN_OS) && !defined(_DEBUG) 
 201 #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; } 
 207 int kjsmain(int argc
, char** argv
); 
 209 int main(int argc
, char** argv
) 
 211 #if defined(_DEBUG) && PLATFORM(WIN_OS) 
 212     _CrtSetReportFile(_CRT_WARN
, _CRTDBG_FILE_STDERR
); 
 213     _CrtSetReportMode(_CRT_WARN
, _CRTDBG_MODE_FILE
); 
 214     _CrtSetReportFile(_CRT_ERROR
, _CRTDBG_FILE_STDERR
); 
 215     _CrtSetReportMode(_CRT_ERROR
, _CRTDBG_MODE_FILE
); 
 216     _CrtSetReportFile(_CRT_ASSERT
, _CRTDBG_FILE_STDERR
); 
 217     _CrtSetReportMode(_CRT_ASSERT
, _CRTDBG_MODE_FILE
); 
 222         res 
= kjsmain(argc
, argv
); 
 227 static GlobalImp
* createGlobalObject() 
 229   GlobalImp
* global 
= new GlobalImp
; 
 231   // add debug() function 
 232   global
->put(global
->globalExec(), "debug", new TestFunctionImp(TestFunctionImp::Debug
, 1)); 
 233   // add "print" for compatibility with the mozilla js shell 
 234   global
->put(global
->globalExec(), "print", new TestFunctionImp(TestFunctionImp::Print
, 1)); 
 235   // add "quit" for compatibility with the mozilla js shell 
 236   global
->put(global
->globalExec(), "quit", new TestFunctionImp(TestFunctionImp::Quit
, 0)); 
 237   // add "gc" for compatibility with the mozilla js shell 
 238   global
->put(global
->globalExec(), "gc", new TestFunctionImp(TestFunctionImp::GC
, 0)); 
 239   // add "version" for compatibility with the mozilla js shell  
 240   global
->put(global
->globalExec(), "version", new TestFunctionImp(TestFunctionImp::Version
, 1)); 
 241   global
->put(global
->globalExec(), "run", new TestFunctionImp(TestFunctionImp::Run
, 1)); 
 242   global
->put(global
->globalExec(), "load", new TestFunctionImp(TestFunctionImp::Load
, 1)); 
 244   Interpreter::setShouldPrintExceptions(true); 
 248 static bool prettyPrintScript(const UString
& fileName
, const Vector
<char>& script
) 
 253   RefPtr
<ProgramNode
> programNode 
= parser().parse
<ProgramNode
>(makeSource(script
.data(), fileName
), &errLine
, &errMsg
); 
 255     fprintf(stderr
, "%s:%d: %s.\n", fileName
.UTF8String().c_str(), errLine
, errMsg
.UTF8String().c_str()); 
 259   printf("%s\n", programNode
->toString().UTF8String().c_str()); 
 263 static bool runWithScripts(const Vector
<UString
>& fileNames
, bool prettyPrint
) 
 265   GlobalImp
* globalObject 
= createGlobalObject(); 
 270   for (size_t i 
= 0; i 
< fileNames
.size(); i
++) { 
 271     UString fileName 
= fileNames
[i
]; 
 273     if (!fillBufferWithContentsOfFile(fileName
, script
)) 
 274       return false; // fail early so we can catch missing files 
 277       prettyPrintScript(fileName
, script
); 
 279       Completion completion 
= Interpreter::evaluate(globalObject
->globalExec(), makeSource(script
.data(), fileName
)); 
 280       success 
= success 
&& completion
.complType() != Throw
; 
 286 static void parseArguments(int argc
, char** argv
, Vector
<UString
>& fileNames
, bool& prettyPrint
) 
 289     fprintf(stderr
, "Usage: testkjs file1 [file2...]\n"); 
 293   for (int i 
= 1; i 
< argc
; i
++) { 
 294     const char* fileName 
= argv
[i
]; 
 295     if (strcmp(fileName
, "-f") == 0) // mozilla test driver script uses "-f" prefix for files 
 297     if (strcmp(fileName
, "-p") == 0) { 
 301     fileNames
.append(fileName
); 
 305 int kjsmain(int argc
, char** argv
) 
 309   bool prettyPrint 
= false; 
 310   Vector
<UString
> fileNames
; 
 311   parseArguments(argc
, argv
, fileNames
, prettyPrint
); 
 313   bool success 
= runWithScripts(fileNames
, prettyPrint
); 
 316   Collector::collect(); 
 319   return success 
? 0 : 3; 
 322 static bool fillBufferWithContentsOfFile(const UString
& fileName
, Vector
<char>& buffer
) 
 324   FILE* f 
= fopen(fileName
.UTF8String().c_str(), "r"); 
 326     fprintf(stderr
, "Could not open file: %s\n", fileName
.UTF8String().c_str()); 
 330   size_t buffer_size 
= 0; 
 331   size_t buffer_capacity 
= 1024; 
 333   buffer
.resize(buffer_capacity
); 
 335   while (!feof(f
) && !ferror(f
)) { 
 336     buffer_size 
+= fread(buffer
.data() + buffer_size
, 1, buffer_capacity 
- buffer_size
, f
); 
 337     if (buffer_size 
== buffer_capacity
) { // guarantees space for trailing '\0' 
 338       buffer_capacity 
*= 2; 
 339       buffer
.resize(buffer_capacity
); 
 343   buffer
[buffer_size
] = '\0';