diff options
-rw-r--r-- | main.cpp | 118 | ||||
-rw-r--r-- | qmljs_objects.cpp | 144 | ||||
-rw-r--r-- | qmljs_objects.h | 14 |
3 files changed, 158 insertions, 118 deletions
@@ -61,19 +61,6 @@ #include <sys/mman.h> #include <iostream> -static inline bool protect(const void *addr, size_t size) -{ - size_t pageSize = sysconf(_SC_PAGESIZE); - size_t iaddr = reinterpret_cast<size_t>(addr); - size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1)); - int mode = PROT_READ | PROT_WRITE | PROT_EXEC; - return mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode) == 0; -} - -static int evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, - const QString &source, bool useInterpreter, - QQmlJS::Codegen::Mode mode = QQmlJS::Codegen::GlobalCode); - namespace builtins { using namespace QQmlJS::VM; @@ -94,20 +81,6 @@ struct Print: FunctionObject } }; -struct Eval: FunctionObject -{ - 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, useInterpreter, QQmlJS::Codegen::EvalCode); - } - -private: - bool useInterpreter; -}; - struct TestHarnessError: FunctionObject { TestHarnessError(Context *scope, bool &errorInTestHarness): FunctionObject(scope), errorOccurred(errorInTestHarness) {} @@ -226,92 +199,6 @@ int evaluateCompiledCode(const QStringList &files) #endif -static int evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, - const QString &source, bool useInterpreter, - QQmlJS::Codegen::Mode mode) -{ - using namespace QQmlJS; - - VM::ExecutionEngine *vm = ctx->engine; - IR::Module module; - IR::Function *globalCode = 0; - - const size_t codeSize = 400 * getpagesize(); - uchar *code = 0; - if (posix_memalign((void**)&code, 16, codeSize)) - assert(!"memalign failed"); - assert(code); - assert(! (size_t(code) & 15)); - - { - QQmlJS::Engine ee, *engine = ⅇ - Lexer lexer(engine); - lexer.setCode(source, 1, false); - Parser parser(engine); - - const bool parsed = parser.parseProgram(); - - foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) { - std::cerr << qPrintable(fileName) << ':' << m.loc.startLine << ':' << m.loc.startColumn - << ": error: " << qPrintable(m.message) << std::endl; - } - - if (parsed) { - using namespace AST; - Program *program = AST::cast<Program *>(parser.rootNode()); - - Codegen cg; - globalCode = cg(program, &module, mode); - - if (useInterpreter) { - Moth::InstructionSelection isel(vm, &module, code); - foreach (IR::Function *function, module.functions) - isel(function); - } else { - foreach (IR::Function *function, module.functions) { - MASM::InstructionSelection isel(vm, &module, code); - isel(function); - } - - if (! protect(code, codeSize)) - Q_UNREACHABLE(); - } - } - - if (! globalCode) - return EXIT_FAILURE; - } - - if (!ctx->activation) - ctx->activation = new QQmlJS::VM::Object(); - - foreach (const QString *local, globalCode->locals) { - ctx->activation->__put__(ctx, *local, QQmlJS::VM::Value::undefinedValue()); - } - - void * buf = __qmljs_create_exception_handler(ctx); - if (setjmp(*(jmp_buf *)buf)) { - if (VM::ErrorObject *e = ctx->result.asErrorObject()) - 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 EXIT_FAILURE; - } - - if (useInterpreter) { - Moth::VME vme; - vme(ctx, code); - } else { - globalCode->code(ctx, globalCode->codeData); - } - - if (! ctx->result.isUndefined()) { - 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[]) { @@ -401,9 +288,6 @@ int main(int argc, char *argv[]) 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")), @@ -415,7 +299,7 @@ int main(int argc, char *argv[]) const QString code = QString::fromUtf8(file.readAll()); file.close(); - int exitCode = evaluate(vm.rootContext, fn, code, useInterpreter); + int exitCode = QQmlJS::VM::EvalFunction::evaluate(vm.rootContext, fn, code, useInterpreter, QQmlJS::Codegen::GlobalCode); if (exitCode != EXIT_SUCCESS) return exitCode; if (errorInTestHarness) diff --git a/qmljs_objects.cpp b/qmljs_objects.cpp index 574e1bd897..622ef621b1 100644 --- a/qmljs_objects.cpp +++ b/qmljs_objects.cpp @@ -43,10 +43,20 @@ #include "qmljs_objects.h" #include "qv4ir_p.h" #include "qv4ecmaobjects_p.h" + +#include <private/qqmljsengine_p.h> +#include <private/qqmljslexer_p.h> +#include <private/qqmljsparser_p.h> +#include <private/qqmljsast_p.h> +#include <qv4ir_p.h> +#include <qv4codegen_p.h> +#include <qv4isel_masm_p.h> + #include <QtCore/qmath.h> #include <QtCore/QDebug> #include <cassert> #include <typeinfo> +#include <iostream> using namespace QQmlJS::VM; @@ -448,6 +458,137 @@ void ScriptFunction::call(VM::Context *ctx) function->code(ctx, function->codeData); } + +Value EvalFunction::call(Context *context, Value thisObject, Value *args, int argc, bool strictMode) +{ + Value s = context->argument(0); + if (!s.isString()) { + context->result = s; + return s; + } + const QString code = context->argument(0).stringValue()->toQString(); + + // ### how to determine this correctly + bool directCall = true; + + Context k, *ctx; + if (!directCall) { + // ### + } else if (strictMode) { + ctx = &k; + ctx->initCallContext(context, context->thisObject, this, args, argc); + } else { + ctx = context; + } + // ##### inline and do this in the correct scope + evaluate(ctx, QStringLiteral("eval code"), code, /*useInterpreter*/ false, QQmlJS::Codegen::EvalCode); + + if (strictMode) + ctx->leaveCallContext(); +} + +static inline bool protect(const void *addr, size_t size) +{ + size_t pageSize = sysconf(_SC_PAGESIZE); + size_t iaddr = reinterpret_cast<size_t>(addr); + size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1)); + int mode = PROT_READ | PROT_WRITE | PROT_EXEC; + return mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode) == 0; +} + + +int EvalFunction::evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, + const QString &source, bool useInterpreter, + QQmlJS::Codegen::Mode mode) +{ + using namespace QQmlJS; + + VM::ExecutionEngine *vm = ctx->engine; + IR::Module module; + IR::Function *globalCode = 0; + + const size_t codeSize = 400 * getpagesize(); + uchar *code = 0; + if (posix_memalign((void**)&code, 16, codeSize)) + assert(!"memalign failed"); + assert(code); + assert(! (size_t(code) & 15)); + + { + QQmlJS::Engine ee, *engine = ⅇ + Lexer lexer(engine); + lexer.setCode(source, 1, false); + Parser parser(engine); + + const bool parsed = parser.parseProgram(); + + foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) { + std::cerr << qPrintable(fileName) << ':' << m.loc.startLine << ':' << m.loc.startColumn + << ": error: " << qPrintable(m.message) << std::endl; + } + + if (parsed) { + using namespace AST; + Program *program = AST::cast<Program *>(parser.rootNode()); + + Codegen cg; + globalCode = cg(program, &module, mode); + +// if (useInterpreter) { +// Moth::InstructionSelection isel(vm, &module, code); +// foreach (IR::Function *function, module.functions) +// isel(function); +// } else + { + foreach (IR::Function *function, module.functions) { + MASM::InstructionSelection isel(vm, &module, code); + isel(function); + } + + if (! protect(code, codeSize)) + Q_UNREACHABLE(); + } + } + + if (! globalCode) + return EXIT_FAILURE; + } + + if (!ctx->activation) + ctx->activation = new QQmlJS::VM::Object(); + + foreach (const QString *local, globalCode->locals) { + ctx->activation->__put__(ctx, *local, QQmlJS::VM::Value::undefinedValue()); + } + + if (mode == Codegen::GlobalCode) { + void * buf = __qmljs_create_exception_handler(ctx); + if (setjmp(*(jmp_buf *)buf)) { + if (VM::ErrorObject *e = ctx->result.asErrorObject()) + 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 EXIT_FAILURE; + } + } + +// if (useInterpreter) { +// Moth::VME vme; +// vme(ctx, code); +// } else + { + globalCode->code(ctx, globalCode->codeData); + } + + if (! ctx->result.isUndefined()) { + if (! qgetenv("SHOW_EXIT_VALUE").isEmpty()) + std::cout << "exit value: " << qPrintable(ctx->result.toString(ctx)->toQString()) << std::endl; + } + + return EXIT_SUCCESS; +} + + Value RegExpObject::__get__(Context *ctx, String *name) { QString n = name->toQString(); @@ -661,6 +802,9 @@ ExecutionEngine::ExecutionEngine() glo->__put__(rootContext, identifier(QStringLiteral("undefined")), Value::undefinedValue()); glo->__put__(rootContext, identifier(QStringLiteral("NaN")), Value::fromDouble(nan(""))); glo->__put__(rootContext, identifier(QStringLiteral("Infinity")), Value::fromDouble(INFINITY)); + glo->__put__(rootContext, identifier(QStringLiteral("eval")), Value::fromObject(new EvalFunction(rootContext))); + + } Context *ExecutionEngine::newContext() diff --git a/qmljs_objects.h b/qmljs_objects.h index 490eae2eef..3e06440b68 100644 --- a/qmljs_objects.h +++ b/qmljs_objects.h @@ -43,6 +43,7 @@ #include "qmljs_runtime.h" #include "qv4array_p.h" +#include "qv4codegen_p.h" #include <QtCore/QString> #include <QtCore/QHash> @@ -494,7 +495,7 @@ struct FunctionObject: Object { virtual bool hasInstance(Context *ctx, const Value &value); Value construct(Context *context, Value *args, int argc); - Value call(Context *context, Value thisObject, Value *args, int argc, bool strictMode = false); + virtual Value call(Context *context, Value thisObject, Value *args, int argc, bool strictMode = false); protected: virtual void call(Context *ctx); @@ -519,6 +520,17 @@ struct ScriptFunction: FunctionObject { virtual void construct(Context *ctx); }; +struct EvalFunction : FunctionObject +{ + EvalFunction(Context *scope): FunctionObject(scope) {} + + static int evaluate(QQmlJS::VM::Context *ctx, const QString &fileName, + const QString &source, bool useInterpreter, + QQmlJS::Codegen::Mode mode); + + virtual Value call(Context *context, Value thisObject, Value *args, int argc, bool strictMode = false); +}; + struct RegExpObject: Object { QRegularExpression value; Value lastIndex; |