return mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode) == 0;
}
+namespace builtins {
+using namespace QQmlJS::VM;
+struct Print: FunctionObject
+{
+ 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;
+ }
+};
+} // builtins
+
int main(int argc, char *argv[])
{
using namespace QQmlJS;
QHash<QString, IR::Function *> codeByName;
foreach (IR::Function *function, module.functions) {
isel(function);
- if (function->name && ! function->name->isEmpty())
+ if (function->name && ! function->name->isEmpty()) {
codeByName.insert(*function->name, function);
+ }
}
if (! protect(code, codeSize))
Q_UNREACHABLE();
VM::Context *ctx = new VM::Context;
- ctx->activation = VM::Value::object(ctx, new VM::ArgumentsObject);
+ ctx->activation = VM::Value::object(ctx, new VM::ArgumentsObject(ctx));
+ ctx->activation.objectValue->put(VM::String::get(ctx, QLatin1String("print")),
+ VM::Value::object(ctx, new builtins::Print()));
+ foreach (IR::Function *function, module.functions) {
+ if (function->name && ! function->name->isEmpty()) {
+ ctx->activation.objectValue->put(VM::String::get(ctx, *function->name),
+ VM::Value::object(ctx, new VM::ScriptFunction(function)));
+ }
+ }
codeByName.value(QLatin1String("%entry"))->code(ctx);
}
}
#include "qmljs_objects.h"
+#include "qv4ir_p.h"
+#include <QtCore/QDebug>
#include <cassert>
using namespace QQmlJS::VM;
return false;
}
-Value FunctionObject::call(const Value &thisObject, const Value args[], unsigned argc)
+void FunctionObject::call(Context *ctx)
{
- Q_UNUSED(thisObject);
- Q_UNUSED(args);
- Q_UNUSED(argc);
+ Q_UNUSED(ctx);
+}
+
+void FunctionObject::construct(Context *ctx)
+{
+ Q_UNUSED(ctx);
+ Q_UNIMPLEMENTED();
+}
- Value v;
- __qmljs_init_undefined(0, &v);
- return v;
+void ScriptFunction::call(VM::Context *ctx)
+{
+ // bind the actual arguments. ### slow
+ for (int i = 0; i < function->formals.size(); ++i) {
+ const QString *f = function->formals.at(i);
+ ctx->activation.objectValue->put(String::get(ctx, *f), ctx->arguments[i]);
+ }
+ function->code(ctx);
}
-Value FunctionObject::construct(const Value args[], unsigned argc)
+Property *ArgumentsObject::getOwnProperty(String *name)
{
- Value thisObject;
- __qmljs_init_object(0, &thisObject, new Object);
- call(thisObject, args, argc);
- return thisObject;
+ if (Property *prop = Object::getOwnProperty(name))
+ return prop;
+ else if (context && context->scope)
+ return context->scope->getOwnProperty(name);
+ return 0;
}
#include <cassert>
namespace QQmlJS {
+
+namespace IR {
+struct Function;
+}
+
namespace VM {
struct Value;
virtual FunctionObject *asFunctionObject() { return this; }
virtual bool hasInstance(const Value &value) const;
- virtual Value call(const Value &thisObject, const Value args[], unsigned argc);
- virtual Value construct(const Value args[], unsigned argc);
+ virtual void call(Context *ctx);
+ virtual void construct(Context *ctx);
+};
+
+struct ScriptFunction: FunctionObject {
+ IR::Function *function;
+
+ ScriptFunction(IR::Function *function): function(function) {}
+ virtual void call(Context *ctx);
};
struct ErrorObject: Object {
};
struct ArgumentsObject: Object {
+ Context *context;
+ ArgumentsObject(Context *context): context(context) {}
+ virtual Property *getOwnProperty(String *name);
};
struct Context {
+ Context *parent;
Value activation;
Value thisObject;
Object *scope;
Value *arguments;
- unsigned argumentCount;
+ size_t argumentCount;
+ Value result;
Context()
- : scope(0)
+ : parent(0)
+ , scope(0)
, arguments(0)
, argumentCount(0)
{
activation.type = NULL_TYPE;
thisObject.type = NULL_TYPE;
+ result.type = UNDEFINED_TYPE;
}
};
#include "qmljs_runtime.h"
#include "qmljs_objects.h"
+#include <QtCore/QDebug>
#include <cstdio>
#include <cassert>
return false;
}
-void __qmljs_call(Context *ctx, Value *result, const Value *function,
- const Value *thisObject, const Value *arguments, int argc)
+Context *__qmljs_new_context(Context *current, Value *thisObject, size_t argc)
{
- if (function->type != OBJECT_TYPE) {
- __qmljs_throw_type_error(ctx, result);
- } else if (FunctionObject *f = function->objectValue->asFunctionObject()) {
- *result = f->call(*thisObject, arguments, argc);
- } else {
- __qmljs_throw_type_error(ctx, result);
- }
+ Context *ctx = new Context;
+ ctx->parent = current;
+ ctx->scope = current->activation.objectValue;
+ __qmljs_init_object(ctx, &ctx->activation, new ArgumentsObject(ctx));
+ if (thisObject)
+ ctx->thisObject = *thisObject;
+ else
+ __qmljs_init_null(ctx, &ctx->thisObject);
+ ctx->arguments = new Value[argc];
+ ctx->argumentCount = argc;
+ return ctx;
}
-void __qmjs_construct(Context *ctx, Value *result, const Value *function, const Value *arguments, int argc)
-{
- if (function->type != OBJECT_TYPE) {
- __qmljs_throw_type_error(ctx, result);
- } else if (FunctionObject *f = function->objectValue->asFunctionObject()) {
- *result = f->construct(arguments, argc);
- } else {
- __qmljs_throw_type_error(ctx, result);
- }
+void __qmljs_dispose_context(Context *ctx)
+{
+ delete[] ctx->arguments;
+ delete ctx;
}
+void __qmljs_call_activation_property(Context *context, Value *result, String *name)
+{
+ Value func;
+ context->parent->activation.objectValue->get(name, &func);
+ if (func.type == OBJECT_TYPE) {
+ if (FunctionObject *f = func.objectValue->asFunctionObject()) {
+ f->call(context);
+ __qmljs_copy(result, &context->result);
+ } else {
+ Q_ASSERT(!"not a function");
+ }
+ } else {
+ Q_ASSERT(!"not a callable object");
+ }
+}
} // extern "C"
extern "C" {
+// context
+Context *__qmljs_new_context(Context *current, Value *thisObject, size_t argc);
+void __qmljs_dispose_context(Context *ctx);
+void __qmljs_call_activation_property(Context *, Value *result, String *name);
+
// constructors
void __qmljs_init_undefined(Context *ctx, Value *result);
void __qmljs_init_null(Context *ctx, Value *result);
void __qmljs_se(Context *ctx, Value *result, const Value *left, const Value *right);
void __qmljs_sne(Context *ctx, Value *result, const Value *left, const Value *right);
-void __qmljs_call(Context *ctx, Value *result, const Value *function, const Value *thisObject, const Value *arguments, int argc);
-void __qmjs_construct(Context *ctx, Value *result, const Value *function, const Value *arguments, int argc);
-
} // extern "C"
struct Value {
inline void __qmljs_gt(Context *ctx, Value *result, const Value *left, const Value *right)
{
- __qmljs_compare(ctx, result, right, left, false);
+ __qmljs_compare(ctx, result, left, right, false);
if (result->type == UNDEFINED_TYPE)
__qmljs_init_boolean(ctx, result, false);
inline void __qmljs_ge(Context *ctx, Value *result, const Value *left, const Value *right)
{
- __qmljs_compare(ctx, result, left, right, false);
+ __qmljs_compare(ctx, result, right, left, false);
bool r = ! (result->type == UNDEFINED_TYPE ||
(result->type == BOOLEAN_TYPE && result->booleanValue == true));
(*args_it)->init(actual);
args_it = &(*args_it)->next;
}
- _expr.code = _block->CALL(*base, args);
+ const unsigned t = _block->newTemp();
+ _block->MOVE(_block->TEMP(t), _block->CALL(*base, args));
+ _expr.code = _block->TEMP(t);
return false;
}
void InstructionSelection::operator()(IR::Function *function)
{
+ _code = _codePtr;
_code = (uchar *) ((size_t(_code) + 15) & ~15);
function->code = (void (*)(VM::Context *)) _code;
_codePtr = _code;
amd64_lea_membase(_codePtr, reg, AMD64_RSP, sizeof(Value) * (t->index - 1));
}
-void __qmljs_print(Context *ctx, const Value *args, size_t argc)
+void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *result)
{
- for (int i = 0; i < argc; ++i) {
- Value v;
- __qmljs_to_string(ctx, &v, &args[i]);
- if (i)
- std::cout << ' ';
- std::cout << qPrintable(v.stringValue->text());
+ int argc = 0;
+ for (IR::ExprList *it = call->args; it; it = it->next)
+ ++argc;
+
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
+ amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_RSI, AMD64_RSI);
+ amd64_mov_reg_imm(_codePtr, AMD64_RDX, argc);
+ amd64_call_code(_codePtr, __qmljs_new_context);
+
+ amd64_mov_reg_reg(_codePtr, AMD64_R15, AMD64_RAX, 8);
+
+ argc = 0;
+ for (IR::ExprList *it = call->args; it; it = it->next) {
+ IR::Temp *t = it->expr->asTemp();
+ Q_ASSERT(t != 0);
+ amd64_mov_reg_membase(_codePtr, AMD64_RAX, AMD64_R15, offsetof(Context, arguments), 8);
+ amd64_lea_membase(_codePtr, AMD64_RDI, AMD64_RAX, argc * sizeof(Value));
+ loadTempAddress(AMD64_RSI, t);
+ amd64_call_code(_codePtr, __qmljs_copy);
+ ++argc;
}
- std::cout << std::endl;
+
+ String *id = identifier(*call->base->asName()->id);
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
+ loadTempAddress(AMD64_RSI, result);
+ amd64_mov_reg_imm(_codePtr, AMD64_RDX, id);
+ amd64_call_code(_codePtr, __qmljs_call_activation_property);
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
+ amd64_call_code(_codePtr, __qmljs_dispose_context);
}
-void InstructionSelection::visitExp(IR::Exp *s)
+void InstructionSelection::visitExp(IR::Exp *)
{
- if (IR::Call *c = s->expr->asCall()) {
- IR::Name *n = c->base->asName();
- if (n && *n->id == QLatin1String("print")) {
- int argc = 0;
- for (IR::ExprList *it = c->args; it; it = it->next)
- ++argc;
- amd64_mov_reg_imm(_codePtr, AMD64_RDI, argc * sizeof(Value));
- amd64_mov_reg_imm(_codePtr, AMD64_RAX, malloc);
- amd64_call_reg(_codePtr, AMD64_RAX);
- amd64_mov_reg_reg(_codePtr, AMD64_R15, AMD64_RAX, 8);
-
- argc = 0;
- for (IR::ExprList *it = c->args; it; it = it->next) {
- IR::Temp *t = it->expr->asTemp();
- Q_ASSERT(t != 0);
- amd64_lea_membase(_codePtr, AMD64_RDI, AMD64_R15, argc * sizeof(Value));
- loadTempAddress(AMD64_RSI, t);
- amd64_call_code(_codePtr, __qmljs_copy);
- ++argc;
- }
-
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
- amd64_mov_reg_reg(_codePtr, AMD64_RSI, AMD64_R15, 8);
- amd64_mov_reg_imm(_codePtr, AMD64_RDX, argc);
- amd64_call_code(_codePtr, __qmljs_print);
-
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
- amd64_mov_reg_imm(_codePtr, AMD64_RAX, free);
- amd64_call_reg(_codePtr, AMD64_RAX);
- return;
- }
- }
- Q_UNIMPLEMENTED();
- assert(!"TODO");
+// Q_UNIMPLEMENTED();
+// assert(!"TODO");
}
void InstructionSelection::visitEnter(IR::Enter *)
assert(!"TODO");
}
return;
+ } else if (IR::Temp *t2 = s->source->asTemp()) {
+ loadTempAddress(AMD64_RDI, t);
+ loadTempAddress(AMD64_RSI, t2);
+ amd64_call_code(_codePtr, __qmljs_copy);
+ return;
} else if (IR::String *str = s->source->asString()) {
amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
loadTempAddress(AMD64_RSI, t);
amd64_call_code(_codePtr, op);
return;
}
+ } else if (IR::Call *c = s->source->asCall()) {
+ if (c->base->asName()) {
+ callActivationProperty(c, t);
+ return;
+ }
}
}
} else {
void InstructionSelection::visitRet(IR::Ret *s)
{
+ if (IR::Temp *t = s->expr->asTemp()) {
+ amd64_lea_membase(_codePtr, AMD64_RDI, AMD64_R14, offsetof(Context, result));
+ loadTempAddress(AMD64_RSI, t);
+ amd64_call_code(_codePtr, __qmljs_copy);
+ return;
+ }
Q_UNIMPLEMENTED();
Q_UNUSED(s);
}
VM::String *identifier(const QString &s);
int tempOffset(IR::Temp *t);
void loadTempAddress(int reg, IR::Temp *t);
+ void callActivationProperty(IR::Call *call, IR::Temp *result);
virtual void visitExp(IR::Exp *);
virtual void visitEnter(IR::Enter *);