#include "qmljs_objects.h" #include "qv4codegen_p.h" #include "qv4isel_p.h" #include "qv4syntaxchecker_p.h" #include #include #include #include #include #include #include static inline bool protect(const void *addr, size_t size) { size_t pageSize = sysconf(_SC_PAGESIZE); size_t iaddr = reinterpret_cast(addr); size_t roundAddr = iaddr & ~(pageSize - static_cast(1)); int mode = PROT_READ | PROT_WRITE | PROT_EXEC; return mprotect(reinterpret_cast(roundAddr), size + (iaddr - roundAddr), mode) == 0; } namespace builtins { using namespace QQmlJS::VM; struct Print: FunctionObject { Print(Context *scope): FunctionObject(scope) {} virtual void call(Context *ctx) { for (size_t i = 0; i < ctx->argumentCount; ++i) { Value v; __qmljs_to_string(ctx, &v, &ctx->arguments[i]); if (i) std::cout << ' '; std::cout << qPrintable(v.stringValue->text()); } std::cout << std::endl; } }; struct ObjectCtor: FunctionObject { ObjectCtor(Context *scope): FunctionObject(scope) {} virtual void construct(Context *ctx) { __qmljs_init_object(ctx, &ctx->thisObject, new Object()); } virtual void call(Context *) { assert(!"not here"); } }; struct StringCtor: FunctionObject { StringCtor(Context *scope): FunctionObject(scope) {} virtual void construct(Context *ctx) { Value arg = ctx->argument(0); __qmljs_to_string(ctx, &arg, &arg); __qmljs_init_object(ctx, &ctx->thisObject, new StringObject(arg)); } virtual void call(Context *ctx) { const Value arg = ctx->argument(0); if (arg.is(UNDEFINED_TYPE)) __qmljs_init_string(ctx, &ctx->result, String::get(ctx, QString())); else __qmljs_to_string(ctx, &ctx->result, &arg); } }; struct StringPrototype: Object { StringPrototype(Context *ctx, FunctionObject *ctor) { setProperty(ctx, QLatin1String("constructor"), Value::object(ctx, ctor)); setProperty(ctx, QLatin1String("toString"), toString); } void setProperty(Context *ctx, const QString &name, const Value &value) { put(String::get(ctx, name), value); } void setProperty(Context *ctx, const QString &name, void (*code)(Context *)) { setProperty(ctx, name, Value::object(ctx, new NativeFunction(ctx, code))); } static void toString(Context *ctx) { __qmljs_to_string(ctx, &ctx->result, &ctx->thisObject); } }; } // builtins void evaluate(QQmlJS::Engine *engine, const QString &fileName, const QString &code) { using namespace QQmlJS; Lexer lexer(engine); lexer.setCode(code, 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(parser.rootNode()); Codegen cg; IR::Module module; cg(program, &module); const size_t codeSize = 10 * getpagesize(); uchar *code = (uchar *) malloc(codeSize); x86_64::InstructionSelection isel(&module, code); QHash codeByName; foreach (IR::Function *function, module.functions) { isel(function); if (function->name && ! function->name->isEmpty()) { codeByName.insert(*function->name, function); } } if (! protect(code, codeSize)) Q_UNREACHABLE(); VM::Context *ctx = new VM::Context; ctx->init(); VM::String *prototype = VM::String::get(ctx, QLatin1String("prototype")); VM::Object *globalObject = new VM::ArgumentsObject(ctx); __qmljs_init_object(ctx, &ctx->activation, globalObject); globalObject->put(VM::String::get(ctx, QLatin1String("print")), VM::Value::object(ctx, new builtins::Print(ctx))); globalObject->put(VM::String::get(ctx, QLatin1String("Object")), VM::Value::object(ctx, new builtins::ObjectCtor(ctx))); VM::FunctionObject *stringCtor = new builtins::StringCtor(ctx); stringCtor->put(prototype, VM::Value::object(ctx, new builtins::StringPrototype(ctx, stringCtor))); globalObject->put(VM::String::get(ctx, QLatin1String("String")), VM::Value::object(ctx, stringCtor)); foreach (IR::Function *function, module.functions) { if (function->name && ! function->name->isEmpty()) { globalObject->put(VM::String::get(ctx, *function->name), VM::Value::object(ctx, new VM::ScriptFunction(ctx, function))); } } codeByName.value(QLatin1String("%entry"))->code(ctx); } } int main(int argc, char *argv[]) { using namespace QQmlJS; QCoreApplication app(argc, argv); QStringList args = app.arguments(); args.removeFirst(); Engine engine; foreach (const QString &fn, args) { QFile file(fn); if (file.open(QFile::ReadOnly)) { const QString code = QString::fromUtf8(file.readAll()); file.close(); evaluate(&engine, fn, code); } } }