From a55e56327952b0d6cba11e2573ec122ef98ccad8 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 8 Nov 2012 12:45:40 +0100 Subject: [PATCH] Changed commandline and return codes for test harness. The different backends can now be selected by command-line options, and when none is specified, masm is used. The difference is that the environment variable USE_MOTH is not used anymore. The return codes are 0 or -1, so the test harness can easily check for errors. The ECMA test262 harness uses the $ERROR function to report errors. When the environment variable IN_TEST_HARNESS is set, this function will get added to the global object. Change-Id: I291c72332ea50892afb99f9a0a15004ffc81c200 Reviewed-by: Simon Hausmann --- main.cpp | 163 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 117 insertions(+), 46 deletions(-) diff --git a/main.cpp b/main.cpp index 545806bb29..5bb61a6090 100644 --- a/main.cpp +++ b/main.cpp @@ -70,7 +70,8 @@ static inline bool protect(const void *addr, size_t size) return mprotect(reinterpret_cast(roundAddr), size + (iaddr - roundAddr), mode) == 0; } -static void evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, const QString &source, +static int evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, + const QString &source, bool useInterpreter, QQmlJS::Codegen::Mode mode = QQmlJS::Codegen::GlobalCode); namespace builtins { @@ -95,13 +96,36 @@ struct Print: FunctionObject struct Eval: FunctionObject { - Eval(Context *scope): FunctionObject(scope) {} + Eval(Context *scope, bool useInterpreter): FunctionObject(scope), useInterpreter(useInterpreter) {} virtual void call(Context *ctx) { const QString code = ctx->argument(0).toString(ctx)->toQString(); - evaluate(ctx, QStringLiteral("eval code"), code, QQmlJS::Codegen::EvalCode); + evaluate(ctx, QStringLiteral("eval code"), code, useInterpreter, QQmlJS::Codegen::EvalCode); } + +private: + bool useInterpreter; +}; + +struct TestHarnessError: FunctionObject +{ + TestHarnessError(Context *scope, bool &errorInTestHarness): FunctionObject(scope), errorOccurred(errorInTestHarness) {} + + virtual void call(Context *ctx) + { + errorOccurred = true; + + for (unsigned int i = 0; i < ctx->argumentCount; ++i) { + String *s = ctx->argument(i).toString(ctx); + if (i) + std::cerr << ' '; + std::cerr << qPrintable(s->toQString()); + } + std::cerr << std::endl; + } + + bool &errorOccurred; }; } // builtins @@ -145,7 +169,7 @@ int compileFiles(const QStringList &files) compile(fileName, source); } } - return 0; + return EXIT_SUCCESS; } int evaluateCompiledCode(const QStringList &files) @@ -159,7 +183,7 @@ int evaluateCompiledCode(const QStringList &files) QFunctionPointer ptr = lib.resolve("%entry"); // qDebug("_%%entry resolved to address %p", ptr); if (!ptr) - return -1; + return EXIT_FAILURE; void (*code)(VM::Context *) = (void (*)(VM::Context *)) ptr; VM::ExecutionEngine vm; @@ -175,19 +199,20 @@ int evaluateCompiledCode(const QStringList &files) std::cerr << "Uncaught exception: " << qPrintable(e->value.toString(ctx)->toQString()) << std::endl; else std::cerr << "Uncaught exception: " << qPrintable(ctx->result.toString(ctx)->toQString()) << std::endl; - return -2; + return EXIT_FAILURE; } code(ctx); } - return 0; + return EXIT_SUCCESS; } #endif -static void evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, const QString &source, - QQmlJS::Codegen::Mode mode) +static int evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, + const QString &source, bool useInterpreter, + QQmlJS::Codegen::Mode mode) { using namespace QQmlJS; @@ -202,8 +227,6 @@ static void evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, const QS assert(code); assert(! (size_t(code) & 15)); - static bool useMoth = !qgetenv("USE_MOTH").isNull(); - { QQmlJS::Engine ee, *engine = ⅇ Lexer lexer(engine); @@ -224,7 +247,7 @@ static void evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, const QS Codegen cg; globalCode = cg(program, &module, mode); - if (useMoth) { + if (useInterpreter) { Moth::InstructionSelection isel(vm, &module, code); foreach (IR::Function *function, module.functions) isel(function); @@ -240,7 +263,7 @@ static void evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, const QS } if (! globalCode) - return; + return EXIT_FAILURE; } if (! ctx->activation.isObject()) @@ -256,10 +279,10 @@ static void evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, const QS std::cerr << "Uncaught exception: " << qPrintable(e->value.toString(ctx)->toQString()) << std::endl; else std::cerr << "Uncaught exception: " << qPrintable(ctx->result.toString(ctx)->toQString()) << std::endl; - return; + return EXIT_FAILURE; } - if (useMoth) { + if (useInterpreter) { Moth::VME vme; vme(ctx, code); } else { @@ -267,9 +290,11 @@ static void evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, const QS } if (! ctx->result.isUndefined()) { - if (! qgetenv("SHOW_EXIT_VALUE").isNull()) + if (! qgetenv("SHOW_EXIT_VALUE").isEmpty()) std::cout << "exit value: " << qPrintable(ctx->result.toString(ctx)->toQString()) << std::endl; } + + return EXIT_SUCCESS; } int main(int argc, char *argv[]) @@ -278,38 +303,84 @@ int main(int argc, char *argv[]) QStringList args = app.arguments(); args.removeFirst(); + enum { + use_masm, + use_moth, + use_llvm_compiler, + use_llvm_runtime + } mode = use_masm; + + if (!args.isEmpty()) { + if (args.first() == QLatin1String("--jit")) { + mode = use_masm; + args.removeFirst(); + } + + if (args.first() == QLatin1String("--interpret")) { + mode = use_moth; + args.removeFirst(); + } + #ifndef QMLJS_NO_LLVM - if (args.isEmpty()) { - std::cerr << "Usage: v4 [--compile|--aot] file..." << std::endl; - return 0; - } + if (args.first() == QLatin1String("--compile")) { + mode = use_llvm_compiler; + args.removeFirst(); + } - if (args.first() == QLatin1String("--compile")) { - args.removeFirst(); - return compileFiles(args); - } else if (args.first() == QLatin1String("--aot")) { - args.removeFirst(); - return evaluateCompiledCode(args); - } -#endif - - QQmlJS::VM::ExecutionEngine vm; - QQmlJS::VM::Context *ctx = vm.rootContext; - - QQmlJS::VM::Object *globalObject = vm.globalObject.objectValue(); - globalObject->__put__(ctx, vm.identifier(QStringLiteral("print")), - QQmlJS::VM::Value::fromObject(new builtins::Print(ctx))); - - globalObject->__put__(ctx, vm.identifier(QStringLiteral("eval")), - QQmlJS::VM::Value::fromObject(new builtins::Eval(ctx))); - - foreach (const QString &fn, args) { - QFile file(fn); - if (file.open(QFile::ReadOnly)) { - const QString code = QString::fromUtf8(file.readAll()); - file.close(); - - evaluate(vm.rootContext, fn, code); + if (args.first() == QLatin1String("--aot")) { + mode = use_llvm_runtime; + args.removeFirst(); + } +#endif // QMLJS_NO_LLVM + if (args.first() == QLatin1String("--help")) { + std::cerr << "Usage: v4 [|--jit|--interpret|--compile|--aot] file..." << std::endl; + return EXIT_SUCCESS; } } + + switch (mode) { +#ifdef QMLJS_NO_LLVM + case use_llvm_compiler: + case use_llvm_runtime: + std::cerr << "LLVM backend was not built, compiler is unavailable." << std::endl; + return EXIT_FAILURE; +#else // QMLJS_NO_LLVM + case use_llvm_compiler: + return compileFiles(args); + case use_llvm_runtime: + return evaluateCompiledCode(args); +#endif // QMLJS_NO_LLVM + case use_masm: + case use_moth: { + bool useInterpreter = mode == use_moth; + QQmlJS::VM::ExecutionEngine vm; + QQmlJS::VM::Context *ctx = vm.rootContext; + + QQmlJS::VM::Object *globalObject = vm.globalObject.objectValue(); + globalObject->__put__(ctx, vm.identifier(QStringLiteral("print")), + QQmlJS::VM::Value::fromObject(new builtins::Print(ctx))); + + globalObject->__put__(ctx, vm.identifier(QStringLiteral("eval")), + QQmlJS::VM::Value::fromObject(new builtins::Eval(ctx, useInterpreter))); + + bool errorInTestHarness = false; + if (!qgetenv("IN_TEST_HARNESS").isEmpty()) + globalObject->__put__(ctx, vm.identifier(QStringLiteral("$ERROR")), + QQmlJS::VM::Value::fromObject(new builtins::TestHarnessError(ctx, errorInTestHarness))); + + foreach (const QString &fn, args) { + QFile file(fn); + if (file.open(QFile::ReadOnly)) { + const QString code = QString::fromUtf8(file.readAll()); + file.close(); + + int exitCode = evaluate(vm.rootContext, fn, code, useInterpreter); + if (exitCode != EXIT_SUCCESS) + return exitCode; + if (errorInTestHarness) + return EXIT_FAILURE; + } + } + } return EXIT_SUCCESS; + } }