X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/14957cd040308e3eeec43d26bae5d76da13fcd85..1981f5dfe8d77d97469d20652f712a09400c48ed:/jsc.cpp diff --git a/jsc.cpp b/jsc.cpp index 85ed56b..95bc334 100644 --- a/jsc.cpp +++ b/jsc.cpp @@ -24,13 +24,16 @@ #include "BytecodeGenerator.h" #include "Completion.h" -#include "CurrentTime.h" +#include #include "ExceptionHelpers.h" #include "InitializeThreading.h" +#include "Interpreter.h" #include "JSArray.h" +#include "JSCTypedArrayStubs.h" #include "JSFunction.h" #include "JSLock.h" #include "JSString.h" +#include #include "SamplingTool.h" #include #include @@ -42,8 +45,12 @@ #endif #if HAVE(READLINE) +// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h +// We #define it to something else to avoid this conflict. +#define Function ReadlineFunction #include #include +#undef Function #endif #if HAVE(SYS_TIME_H) @@ -65,14 +72,19 @@ #include #endif +#if CPU(ARM_THUMB2) +#include +#include +#endif + using namespace JSC; using namespace WTF; -static void cleanupGlobalData(JSGlobalData*); static bool fillBufferWithContentsOfFile(const UString& fileName, Vector& buffer); static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*); static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*); +static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*); static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*); #ifndef NDEBUG static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*); @@ -82,6 +94,7 @@ 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 EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*); static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*); #if ENABLE(SAMPLING_FLAGS) @@ -100,8 +113,8 @@ struct Script { } }; -struct Options { - Options() +struct CommandLine { + CommandLine() : interactive(false) , dump(false) { @@ -114,7 +127,6 @@ struct Options { }; static const char interactivePrompt[] = "> "; -static const UString interpreterName("Interpreter"); class StopWatch { public: @@ -143,38 +155,105 @@ long StopWatch::getElapsedMS() } class GlobalObject : public JSGlobalObject { +private: + GlobalObject(JSGlobalData&, Structure*); + public: - GlobalObject(JSGlobalData&, Structure*, const Vector& arguments); - virtual UString className() const { return "global"; } + typedef JSGlobalObject Base; + + static GlobalObject* create(JSGlobalData& globalData, Structure* structure, const Vector& arguments) + { + GlobalObject* object = new (NotNull, allocateCell(globalData.heap)) GlobalObject(globalData, structure); + object->finishCreation(globalData, arguments); + return object; + } + + static const ClassInfo s_info; + + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) + { + return Structure::create(globalData, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info); + } + +protected: + void finishCreation(JSGlobalData& globalData, const Vector& arguments) + { + Base::finishCreation(globalData); + + addFunction(globalData, "debug", functionDebug, 1); + addFunction(globalData, "print", functionPrint, 1); + addFunction(globalData, "quit", functionQuit, 0); + addFunction(globalData, "gc", functionGC, 0); +#ifndef NDEBUG + addFunction(globalData, "releaseExecutableMemory", functionReleaseExecutableMemory, 0); +#endif + addFunction(globalData, "version", functionVersion, 1); + addFunction(globalData, "run", functionRun, 1); + addFunction(globalData, "load", functionLoad, 1); + addFunction(globalData, "checkSyntax", functionCheckSyntax, 1); + addFunction(globalData, "jscStack", functionJSCStack, 1); + addFunction(globalData, "readline", functionReadline, 0); + addFunction(globalData, "preciseTime", functionPreciseTime, 0); +#if ENABLE(SAMPLING_FLAGS) + addFunction(globalData, "setSamplingFlags", functionSetSamplingFlags, 1); + addFunction(globalData, "clearSamplingFlags", functionClearSamplingFlags, 1); +#endif + + addConstructableFunction(globalData, "Uint8Array", constructJSUint8Array, 1); + addConstructableFunction(globalData, "Uint8ClampedArray", constructJSUint8ClampedArray, 1); + addConstructableFunction(globalData, "Uint16Array", constructJSUint16Array, 1); + addConstructableFunction(globalData, "Uint32Array", constructJSUint32Array, 1); + addConstructableFunction(globalData, "Int8Array", constructJSInt8Array, 1); + addConstructableFunction(globalData, "Int16Array", constructJSInt16Array, 1); + addConstructableFunction(globalData, "Int32Array", constructJSInt32Array, 1); + addConstructableFunction(globalData, "Float32Array", constructJSFloat32Array, 1); + addConstructableFunction(globalData, "Float64Array", constructJSFloat64Array, 1); + + JSArray* array = constructEmptyArray(globalExec()); + for (size_t i = 0; i < arguments.size(); ++i) + array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]), false); + putDirect(globalData, Identifier(globalExec(), "arguments"), array); + } + + void addFunction(JSGlobalData& globalData, const char* name, NativeFunction function, unsigned arguments) + { + Identifier identifier(globalExec(), name); + putDirect(globalData, identifier, JSFunction::create(globalExec(), this, arguments, identifier, function)); + } + + void addConstructableFunction(JSGlobalData& globalData, const char* name, NativeFunction function, unsigned arguments) + { + Identifier identifier(globalExec(), name); + putDirect(globalData, identifier, JSFunction::create(globalExec(), this, arguments, identifier, function, NoIntrinsic, function)); + } }; COMPILE_ASSERT(!IsInteger::value, WTF_IsInteger_GlobalObject_false); ASSERT_CLASS_FITS_IN_CELL(GlobalObject); -GlobalObject::GlobalObject(JSGlobalData& globalData, Structure* structure, const Vector& arguments) +const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) }; + +GlobalObject::GlobalObject(JSGlobalData& globalData, Structure* structure) : JSGlobalObject(globalData, structure) { - 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()) 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(globalExec()->globalData(), Identifier(globalExec(), "arguments"), array); +static inline SourceCode jscSource(const char* utf8, const UString& filename) +{ + // Find the the first non-ascii character, or nul. + const char* pos = utf8; + while (*pos > 0) + pos++; + size_t asciiLength = pos - utf8; + + // Fast case - string is all ascii. + if (!*pos) + return makeSource(UString(utf8, asciiLength), filename); + + // Slow case - contains non-ascii characters, use fromUTF8WithLatin1Fallback. + ASSERT(*pos < 0); + ASSERT(strlen(utf8) == asciiLength + strlen(pos)); + String source = String::fromUTF8WithLatin1Fallback(utf8, asciiLength + strlen(pos)); + return makeSource(source.impl(), filename); } EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec) @@ -183,7 +262,7 @@ EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec) if (i) putchar(' '); - printf("%s", exec->argument(i).toString(exec).utf8().data()); + printf("%s", exec->argument(i).toString(exec)->value(exec).utf8().data()); } putchar('\n'); @@ -193,13 +272,29 @@ EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec) EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec) { - fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec).utf8().data()); + fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data()); + return JSValue::encode(jsUndefined()); +} + +EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec) +{ + String trace = "--> Stack trace:\n"; + Vector stackTrace; + Interpreter::getStackTrace(&exec->globalData(), stackTrace); + int i = 0; + + for (Vector::iterator iter = stackTrace.begin(); iter < stackTrace.end(); iter++) { + StackFrame level = *iter; + trace += String::format(" %i %s\n", i, level.toString(exec).utf8().data()); + i++; + } + fprintf(stderr, "%s", trace.utf8().data()); return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec) { - JSLock lock(SilenceAssertionsOnly); + JSLockHolder lock(exec); exec->heap()->collectAllGarbage(); return JSValue::encode(jsUndefined()); } @@ -207,7 +302,7 @@ EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec) #ifndef NDEBUG EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec) { - JSLock lock(SilenceAssertionsOnly); + JSLockHolder lock(exec); exec->globalData().releaseExecutableMemory(); return JSValue::encode(jsUndefined()); } @@ -222,38 +317,46 @@ EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*) EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec) { - UString fileName = exec->argument(0).toString(exec); + UString fileName = exec->argument(0).toString(exec)->value(exec); Vector script; if (!fillBufferWithContentsOfFile(fileName, script)) return JSValue::encode(throwError(exec, createError(exec, "Could not open file."))); - GlobalObject* globalObject = new (&exec->globalData()) GlobalObject(exec->globalData(), GlobalObject::createStructure(exec->globalData(), jsNull()), Vector()); + GlobalObject* globalObject = GlobalObject::create(exec->globalData(), GlobalObject::createStructure(exec->globalData(), jsNull()), Vector()); + JSValue exception; StopWatch stopWatch; stopWatch.start(); - evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName)); + evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script.data(), fileName), JSValue(), &exception); stopWatch.stop(); + if (!!exception) { + throwError(globalObject->globalExec(), exception); + return JSValue::encode(jsUndefined()); + } + return JSValue::encode(jsNumber(stopWatch.getElapsedMS())); } EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec) { - UString fileName = exec->argument(0).toString(exec); + UString fileName = exec->argument(0).toString(exec)->value(exec); Vector script; if (!fillBufferWithContentsOfFile(fileName, script)) 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) - throwError(exec, result.value()); - return JSValue::encode(result.value()); + + JSValue evaluationException; + JSValue result = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), jscSource(script.data(), fileName), JSValue(), &evaluationException); + if (evaluationException) + throwError(exec, evaluationException); + return JSValue::encode(result); } EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec) { - UString fileName = exec->argument(0).toString(exec); + UString fileName = exec->argument(0).toString(exec)->value(exec); Vector script; if (!fillBufferWithContentsOfFile(fileName, script)) return JSValue::encode(throwError(exec, createError(exec, "Could not open file."))); @@ -262,11 +365,13 @@ EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec) StopWatch stopWatch; stopWatch.start(); - Completion result = checkSyntax(globalObject->globalExec(), makeSource(script.data(), fileName)); + + JSValue syntaxException; + bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException); stopWatch.stop(); - if (result.complType() == Throw) - throwError(exec, result.value()); + if (!validSyntax) + throwError(exec, syntaxException); return JSValue::encode(jsNumber(stopWatch.getElapsedMS())); } @@ -306,14 +411,13 @@ EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec) return JSValue::encode(jsString(exec, line.data())); } -EncodedJSValue JSC_HOST_CALL functionQuit(ExecState* exec) +EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*) { - // 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 - // we pretend that execution has terminated to avoid ASSERTs, then tear down the heap. - exec->globalData().dynamicGlobalObject = 0; + return JSValue::encode(jsNumber(currentTime())); +} - cleanupGlobalData(&exec->globalData()); +EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*) +{ exit(EXIT_SUCCESS); #if COMPILER(MSVC) && OS(WINCE) @@ -327,7 +431,7 @@ EncodedJSValue JSC_HOST_CALL functionQuit(ExecState* exec) // be in a separate main function because the jscmain function requires object // unwinding. -#if COMPILER(MSVC) && !defined(_DEBUG) && !OS(WINCE) +#if COMPILER(MSVC) && !COMPILER(INTEL) && !defined(_DEBUG) && !OS(WINCE) #define TRY __try { #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; } #else @@ -335,10 +439,18 @@ EncodedJSValue JSC_HOST_CALL functionQuit(ExecState* exec) #define EXCEPT(x) #endif -int jscmain(int argc, char** argv, JSGlobalData*); +int jscmain(int argc, char** argv); int main(int argc, char** argv) { +#if CPU(ARM_THUMB2) + // Enabled IEEE754 denormal support. + fenv_t env; + fegetenv( &env ); + env.__fpscr &= ~0x01000000u; + fesetenv( &env ); +#endif + #if OS(WINDOWS) #if !OS(WINCE) // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for @@ -364,31 +476,21 @@ int main(int argc, char** argv) #endif // Initialize JSC before getting JSGlobalData. + WTF::initializeMainThread(); JSC::initializeThreading(); // We can't use destructors in the following code because it uses Windows // Structured Exception Handling int res = 0; - JSGlobalData* globalData = JSGlobalData::create(ThreadStackTypeLarge).leakRef(); TRY - res = jscmain(argc, argv, globalData); + res = jscmain(argc, argv); EXCEPT(res = 3) - - cleanupGlobalData(globalData); return res; } -static void cleanupGlobalData(JSGlobalData* globalData) -{ - JSLock lock(SilenceAssertionsOnly); - globalData->clearBuiltinStructures(); - globalData->heap.destroy(); - globalData->deref(); -} - static bool runWithScripts(GlobalObject* globalObject, const Vector