]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - jsc.cpp
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / jsc.cpp
diff --git a/jsc.cpp b/jsc.cpp
index ae47d55994cb061fb696e8a167e812abe4e3084e..85ed56b3f3bd086dce1319a06ff7b9b79f322b6d 100644 (file)
--- a/jsc.cpp
+++ b/jsc.cpp
 #include "BytecodeGenerator.h"
 #include "Completion.h"
 #include "CurrentTime.h"
+#include "ExceptionHelpers.h"
 #include "InitializeThreading.h"
 #include "JSArray.h"
 #include "JSFunction.h"
 #include "JSLock.h"
 #include "JSString.h"
-#include "PrototypeFunction.h"
 #include "SamplingTool.h"
 #include <math.h>
 #include <stdio.h>
@@ -71,19 +71,22 @@ using namespace WTF;
 static void cleanupGlobalData(JSGlobalData*);
 static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer);
 
-static JSValue JSC_HOST_CALL functionPrint(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionDebug(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionGC(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionVersion(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionRun(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionLoad(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionCheckSyntax(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionReadline(ExecState*, JSObject*, JSValue, const ArgList&);
-static NO_RETURN_WITH_VALUE JSValue JSC_HOST_CALL functionQuit(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
+#ifndef NDEBUG
+static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
+#endif
+static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
+static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
 
 #if ENABLE(SAMPLING_FLAGS)
-static JSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*, JSObject*, JSValue, const ArgList&);
-static JSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*, JSObject*, JSValue, const ArgList&);
+static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
 #endif
 
 struct Script {
@@ -141,142 +144,155 @@ long StopWatch::getElapsedMS()
 
 class GlobalObject : public JSGlobalObject {
 public:
-    GlobalObject(const Vector<UString>& arguments);
+    GlobalObject(JSGlobalData&, Structure*, const Vector<UString>& arguments);
     virtual UString className() const { return "global"; }
 };
 COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
 ASSERT_CLASS_FITS_IN_CELL(GlobalObject);
 
-GlobalObject::GlobalObject(const Vector<UString>& arguments)
-    : JSGlobalObject()
+GlobalObject::GlobalObject(JSGlobalData& globalData, Structure* structure, const Vector<UString>& arguments)
+    : JSGlobalObject(globalData, structure)
 {
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "debug"), functionDebug));
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "print"), functionPrint));
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "quit"), functionQuit));
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "gc"), functionGC));
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "version"), functionVersion));
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "run"), functionRun));
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "load"), functionLoad));
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "checkSyntax"), functionCheckSyntax));
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "readline"), functionReadline));
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "debug"), functionDebug));
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "print"), functionPrint));
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 0, Identifier(globalExec(), "quit"), functionQuit));
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 0, Identifier(globalExec(), "gc"), functionGC));
+#ifndef NDEBUG
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 0, Identifier(globalExec(), "releaseExecutableMemory"), functionReleaseExecutableMemory));
+#endif
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "version"), functionVersion));
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "run"), functionRun));
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "load"), functionLoad));
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "checkSyntax"), functionCheckSyntax));
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 0, Identifier(globalExec(), "readline"), functionReadline));
 
 #if ENABLE(SAMPLING_FLAGS)
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "setSamplingFlags"), functionSetSamplingFlags));
-    putDirectFunction(globalExec(), new (globalExec()) NativeFunctionWrapper(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "clearSamplingFlags"), functionClearSamplingFlags));
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "setSamplingFlags"), functionSetSamplingFlags));
+    putDirectFunction(globalExec(), new (globalExec()) JSFunction(globalExec(), this, functionStructure(), 1, Identifier(globalExec(), "clearSamplingFlags"), functionClearSamplingFlags));
 #endif
 
     JSObject* array = constructEmptyArray(globalExec());
     for (size_t i = 0; i < arguments.size(); ++i)
         array->put(globalExec(), i, jsString(globalExec(), arguments[i]));
-    putDirect(Identifier(globalExec(), "arguments"), array);
+    putDirect(globalExec()->globalData(), Identifier(globalExec(), "arguments"), array);
 }
 
-JSValue JSC_HOST_CALL functionPrint(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
 {
-    for (unsigned i = 0; i < args.size(); ++i) {
+    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
         if (i)
             putchar(' ');
 
-        printf("%s", args.at(i).toString(exec).UTF8String().data());
+        printf("%s", exec->argument(i).toString(exec).utf8().data());
     }
 
     putchar('\n');
     fflush(stdout);
-    return jsUndefined();
+    return JSValue::encode(jsUndefined());
 }
 
-JSValue JSC_HOST_CALL functionDebug(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
 {
-    fprintf(stderr, "--> %s\n", args.at(0).toString(exec).UTF8String().data());
-    return jsUndefined();
+    fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec).utf8().data());
+    return JSValue::encode(jsUndefined());
 }
 
-JSValue JSC_HOST_CALL functionGC(ExecState* exec, JSObject*, JSValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
 {
     JSLock lock(SilenceAssertionsOnly);
     exec->heap()->collectAllGarbage();
-    return jsUndefined();
+    return JSValue::encode(jsUndefined());
+}
+
+#ifndef NDEBUG
+EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
+{
+    JSLock lock(SilenceAssertionsOnly);
+    exec->globalData().releaseExecutableMemory();
+    return JSValue::encode(jsUndefined());
 }
+#endif
 
-JSValue JSC_HOST_CALL functionVersion(ExecState*, JSObject*, JSValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
 {
     // We need this function for compatibility with the Mozilla JS tests but for now
     // we don't actually do any version-specific handling
-    return jsUndefined();
+    return JSValue::encode(jsUndefined());
 }
 
-JSValue JSC_HOST_CALL functionRun(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
 {
-    StopWatch stopWatch;
-    UString fileName = args.at(0).toString(exec);
+    UString fileName = exec->argument(0).toString(exec);
     Vector<char> script;
     if (!fillBufferWithContentsOfFile(fileName, script))
-        return throwError(exec, GeneralError, "Could not open file.");
+        return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
 
-    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    GlobalObject* globalObject = new (&exec->globalData()) GlobalObject(exec->globalData(), GlobalObject::createStructure(exec->globalData(), jsNull()), Vector<UString>());
 
+    StopWatch stopWatch;
     stopWatch.start();
     evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
     stopWatch.stop();
 
-    return jsNumber(globalObject->globalExec(), stopWatch.getElapsedMS());
+    return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
 }
 
-JSValue JSC_HOST_CALL functionLoad(ExecState* exec, JSObject* o, JSValue v, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
 {
-    UNUSED_PARAM(o);
-    UNUSED_PARAM(v);
-    UString fileName = args.at(0).toString(exec);
+    UString fileName = exec->argument(0).toString(exec);
     Vector<char> script;
     if (!fillBufferWithContentsOfFile(fileName, script))
-        return throwError(exec, GeneralError, "Could not open file.");
+        return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
 
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     Completion result = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
     if (result.complType() == Throw)
-        exec->setException(result.value());
-    return result.value();
+        throwError(exec, result.value());
+    return JSValue::encode(result.value());
 }
 
-JSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec, JSObject* o, JSValue v, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
 {
-    UNUSED_PARAM(o);
-    UNUSED_PARAM(v);
-    UString fileName = args.at(0).toString(exec);
+    UString fileName = exec->argument(0).toString(exec);
     Vector<char> script;
     if (!fillBufferWithContentsOfFile(fileName, script))
-        return throwError(exec, GeneralError, "Could not open file.");
+        return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
 
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+
+    StopWatch stopWatch;
+    stopWatch.start();
     Completion result = checkSyntax(globalObject->globalExec(), makeSource(script.data(), fileName));
+    stopWatch.stop();
+
     if (result.complType() == Throw)
-        exec->setException(result.value());
-    return result.value();
+        throwError(exec, result.value());
+    return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
 }
 
 #if ENABLE(SAMPLING_FLAGS)
-JSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
 {
-    for (unsigned i = 0; i < args.size(); ++i) {
-        unsigned flag = static_cast<unsigned>(args.at(i).toNumber(exec));
+    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+        unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
         if ((flag >= 1) && (flag <= 32))
             SamplingFlags::setFlag(flag);
     }
-    return jsNull();
+    return JSValue::encode(jsNull());
 }
 
-JSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
 {
-    for (unsigned i = 0; i < args.size(); ++i) {
-        unsigned flag = static_cast<unsigned>(args.at(i).toNumber(exec));
+    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+        unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
         if ((flag >= 1) && (flag <= 32))
             SamplingFlags::clearFlag(flag);
     }
-    return jsNull();
+    return JSValue::encode(jsNull());
 }
 #endif
 
-JSValue JSC_HOST_CALL functionReadline(ExecState* exec, JSObject*, JSValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
 {
     Vector<char, 256> line;
     int c;
@@ -287,10 +303,10 @@ JSValue JSC_HOST_CALL functionReadline(ExecState* exec, JSObject*, JSValue, cons
         line.append(c);
     }
     line.append('\0');
-    return jsString(exec, line.data());
+    return JSValue::encode(jsString(exec, line.data()));
 }
 
-JSValue JSC_HOST_CALL functionQuit(ExecState* exec, JSObject*, JSValue, const ArgList&)
+EncodedJSValue JSC_HOST_CALL functionQuit(ExecState* exec)
 {
     // Technically, destroying the heap in the middle of JS execution is a no-no,
     // but we want to maintain compatibility with the Mozilla test suite, so
@@ -302,7 +318,7 @@ JSValue JSC_HOST_CALL functionQuit(ExecState* exec, JSObject*, JSValue, const Ar
 
 #if COMPILER(MSVC) && OS(WINCE)
     // Without this, Visual Studio will complain that this method does not return a value.
-    return jsUndefined();
+    return JSValue::encode(jsUndefined());
 #endif
 }
 
@@ -311,7 +327,7 @@ JSValue JSC_HOST_CALL functionQuit(ExecState* exec, JSObject*, JSValue, const Ar
 // be in a separate main function because the jscmain function requires object
 // unwinding.
 
-#if COMPILER(MSVC) && !defined(_DEBUG)
+#if COMPILER(MSVC) && !defined(_DEBUG) && !OS(WINCE)
 #define TRY       __try {
 #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
 #else
@@ -323,7 +339,15 @@ int jscmain(int argc, char** argv, JSGlobalData*);
 
 int main(int argc, char** argv)
 {
-#if defined(_DEBUG) && OS(WINDOWS)
+#if OS(WINDOWS)
+#if !OS(WINCE)
+    // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
+    // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
+    // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
+    ::SetErrorMode(0);
+#endif
+
+#if defined(_DEBUG)
     _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
     _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
@@ -332,7 +356,6 @@ int main(int argc, char** argv)
     _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
 #endif
 
-#if COMPILER(MSVC) && !OS(WINCE)
     timeBeginPeriod(1);
 #endif
 
@@ -346,7 +369,7 @@ int main(int argc, char** argv)
     // We can't use destructors in the following code because it uses Windows
     // Structured Exception Handling
     int res = 0;
-    JSGlobalData* globalData = JSGlobalData::create(ThreadStackTypeLarge).releaseRef();
+    JSGlobalData* globalData = JSGlobalData::create(ThreadStackTypeLarge).leakRef();
     TRY
         res = jscmain(argc, argv, globalData);
     EXCEPT(res = 3)
@@ -358,6 +381,7 @@ int main(int argc, char** argv)
 static void cleanupGlobalData(JSGlobalData* globalData)
 {
     JSLock lock(SilenceAssertionsOnly);
+    globalData->clearBuiltinStructures();
     globalData->heap.destroy();
     globalData->deref();
 }
@@ -371,7 +395,7 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scr
     if (dump)
         BytecodeGenerator::setDumpsGeneratedCode(true);
 
-    JSGlobalData* globalData = globalObject->globalData();
+    JSGlobalData& globalData = globalObject->globalData();
 
 #if ENABLE(SAMPLING_FLAGS)
     SamplingFlags::start();
@@ -389,27 +413,30 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scr
             fileName = "[Command Line]";
         }
 
-        globalData->startSampling();
+        globalData.startSampling();
 
         Completion completion = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script, fileName));
         success = success && completion.complType() != Throw;
         if (dump) {
             if (completion.complType() == Throw)
-                printf("Exception: %s\n", completion.value().toString(globalObject->globalExec()).ascii());
+                printf("Exception: %s\n", completion.value().toString(globalObject->globalExec()).utf8().data());
             else
-                printf("End: %s\n", completion.value().toString(globalObject->globalExec()).ascii());
+                printf("End: %s\n", completion.value().toString(globalObject->globalExec()).utf8().data());
         }
 
-        globalData->stopSampling();
+        globalData.stopSampling();
         globalObject->globalExec()->clearException();
     }
 
 #if ENABLE(SAMPLING_FLAGS)
     SamplingFlags::stop();
 #endif
-    globalData->dumpSampleData(globalObject->globalExec());
+    globalData.dumpSampleData(globalObject->globalExec());
 #if ENABLE(SAMPLING_COUNTERS)
     AbstractSamplingCounter::dump();
+#endif
+#if ENABLE(REGEXP_TRACING)
+    globalData.dumpRegExpTrace();
 #endif
     return success;
 }
@@ -443,9 +470,9 @@ static void runInteractive(GlobalObject* globalObject)
         Completion completion = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(line.data(), interpreterName));
 #endif
         if (completion.complType() == Throw)
-            printf("Exception: %s\n", completion.value().toString(globalObject->globalExec()).ascii());
+            printf("Exception: %s\n", completion.value().toString(globalObject->globalExec()).utf8().data());
         else
-            printf("%s\n", completion.value().toString(globalObject->globalExec()).UTF8String().data());
+            printf("%s\n", completion.value().toString(globalObject->globalExec()).utf8().data());
 
         globalObject->globalExec()->clearException();
     }
@@ -525,7 +552,7 @@ int jscmain(int argc, char** argv, JSGlobalData* globalData)
     Options options;
     parseArguments(argc, argv, options, globalData);
 
-    GlobalObject* globalObject = new (globalData) GlobalObject(options.arguments);
+    GlobalObject* globalObject = new (globalData) GlobalObject(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.arguments);
     bool success = runWithScripts(globalObject, options.scripts, options.dump);
     if (options.interactive && success)
         runInteractive(globalObject);
@@ -535,9 +562,9 @@ int jscmain(int argc, char** argv, JSGlobalData* globalData)
 
 static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer)
 {
-    FILE* f = fopen(fileName.UTF8String().data(), "r");
+    FILE* f = fopen(fileName.utf8().data(), "r");
     if (!f) {
-        fprintf(stderr, "Could not open file: %s\n", fileName.UTF8String().data());
+        fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
         return false;
     }
 
@@ -556,5 +583,8 @@ static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>&
     fclose(f);
     buffer[bufferSize] = '\0';
 
+    if (buffer[0] == '#' && buffer[1] == '!')
+        buffer[0] = buffer[1] = '/';
+
     return true;
 }