struct Print: FunctionObject
{
+ Print(Context *scope): FunctionObject(scope) {}
+
virtual void call(Context *ctx)
{
for (size_t i = 0; i < ctx->argumentCount; ++i) {
struct ObjectCtor: FunctionObject
{
+ ObjectCtor(Context *scope): FunctionObject(scope) {}
+
virtual void construct(Context *ctx)
{
- __qmljs_init_object(ctx, &ctx->result, new Object());
+ __qmljs_init_object(ctx, &ctx->thisObject, new Object());
}
virtual void call(Context *)
struct StringCtor: FunctionObject
{
+ StringCtor(Context *scope): FunctionObject(scope) {}
+
virtual void construct(Context *ctx)
{
Value arg = ctx->argument(0);
void setProperty(Context *ctx, const QString &name, void (*code)(Context *))
{
- setProperty(ctx, name, Value::object(ctx, new NativeFunction(code)));
+ setProperty(ctx, name, Value::object(ctx, new NativeFunction(ctx, code)));
}
static void toString(Context *ctx)
__qmljs_init_object(ctx, &ctx->activation, globalObject);
globalObject->put(VM::String::get(ctx, QLatin1String("print")),
- VM::Value::object(ctx, new builtins::Print()));
+ VM::Value::object(ctx, new builtins::Print(ctx)));
globalObject->put(VM::String::get(ctx, QLatin1String("Object")),
- VM::Value::object(ctx, new builtins::ObjectCtor()));
+ VM::Value::object(ctx, new builtins::ObjectCtor(ctx)));
- VM::FunctionObject *stringCtor = new builtins::StringCtor();
+ 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));
call(ctx);
}
-ScriptFunction::ScriptFunction(Context *context, IR::Function *function)
- : context(context)
+ScriptFunction::ScriptFunction(Context *scope, IR::Function *function)
+ : FunctionObject(scope)
, function(function)
{
formalParameterCount = function->formals.size();
void ScriptFunction::construct(VM::Context *ctx)
{
+ __qmljs_init_object(ctx, &ctx->thisObject, new Object());
function->code(ctx);
}
}
if (Value *prop = Object::getProperty(name, attributes))
return prop;
- else if (context && context->scope)
- return context->scope->getProperty(name, attributes);
return 0;
}
};
struct FunctionObject: Object {
- Object *scope;
+ Context *scope;
String **formalParameterList;
size_t formalParameterCount;
- FunctionObject(Object *scope = 0): scope(scope), formalParameterList(0), formalParameterCount(0) {}
+ FunctionObject(Context *scope): scope(scope), formalParameterList(0), formalParameterCount(0) {}
virtual FunctionObject *asFunctionObject() { return this; }
virtual bool hasInstance(const Value &value) const;
struct NativeFunction: FunctionObject {
void (*code)(Context *);
- NativeFunction(void (*code)(Context *)): code(code) {}
+ NativeFunction(Context *scope, void (*code)(Context *)): FunctionObject(scope), code(code) {}
virtual void call(Context *ctx) { code(ctx); }
virtual void construct(Context *ctx) { code(ctx); }
};
struct ScriptFunction: FunctionObject {
- Context *context;
IR::Function *function;
- ScriptFunction(Context *context, IR::Function *function);
+ ScriptFunction(Context *scope, IR::Function *function);
virtual ~ScriptFunction();
virtual void call(Context *ctx);
Context *parent;
Value activation;
Value thisObject;
- Object *scope;
Value *arguments;
size_t argumentCount;
Value result;
size_t formalCount;
bool calledAsConstructor;
+ Value *lookup(String *name) {
+ if (activation.is(OBJECT_TYPE)) {
+ if (Value *prop = activation.objectValue->getProperty(name))
+ return prop;
+ }
+ return parent ? parent->lookup(name) : 0;
+ }
+
inline Value argument(size_t index = 0)
{
Value arg;
void init()
{
parent = 0;
- scope = 0;
arguments = 0;
argumentCount = 0;
activation.type = NULL_TYPE;
#include "qmljs_runtime.h"
#include "qmljs_objects.h"
+#include "qv4ir_p.h"
#include <QtCore/QDebug>
#include <cstdio>
#include <cassert>
void __qmljs_set_property_closure(Context *ctx, Value *object, String *name, IR::Function *function)
{
Value value;
- __qmljs_init_object(ctx, &value, new VM::ScriptFunction(ctx, function));
+ __qmljs_init_closure(ctx, &value, function);
object->objectValue->put(name, value, /*flag*/ 0);
}
void __qmljs_set_activation_property(Context *ctx, String *name, Value *value)
{
- __qmljs_set_property(ctx, &ctx->activation, name, value);
+ if (Value *prop = ctx->lookup(name))
+ __qmljs_copy(prop, value);
+ else
+ ctx->activation.objectValue->put(name, *value);
}
void __qmljs_copy_activation_property(Context *ctx, String *name, String *other)
{
- __qmljs_copy_property(ctx, &ctx->activation, name, &ctx->activation, other);
+ if (Value *source = ctx->lookup(other))
+ __qmljs_set_activation_property(ctx, name, source);
+ else
+ assert(!"reference error");
}
-void __qmljs_set_activation_property_boolean(Context *ctx, String *name, bool value)
+void __qmljs_set_activation_property_boolean(Context *ctx, String *name, bool b)
{
- __qmljs_set_property_boolean(ctx, &ctx->activation, name, value);
+ Value value;
+ __qmljs_init_boolean(ctx, &value, b);
+ __qmljs_set_activation_property(ctx, name, &value);
}
-void __qmljs_set_activation_property_number(Context *ctx, String *name, double value)
+void __qmljs_set_activation_property_number(Context *ctx, String *name, double number)
{
- __qmljs_set_property_number(ctx, &ctx->activation, name, value);
+ Value value;
+ __qmljs_init_number(ctx, &value, number);
+ __qmljs_set_activation_property(ctx, name, &value);
}
-void __qmljs_set_activation_property_string(Context *ctx, String *name, String *value)
+void __qmljs_set_activation_property_string(Context *ctx, String *name, String *string)
{
- __qmljs_set_property_string(ctx, &ctx->activation, name, value);
+ Value value;
+ __qmljs_init_string(ctx, &value, string);
+ __qmljs_set_activation_property(ctx, name, &value);
}
-void __qmljs_set_activation_property_closure(Context *ctx, String *name, IR::Function *value)
+void __qmljs_set_activation_property_closure(Context *ctx, String *name, IR::Function *clos)
{
- __qmljs_set_property_closure(ctx, &ctx->activation, name, value);
+ Value value;
+ __qmljs_init_closure(ctx, &value, clos);
+ __qmljs_set_activation_property(ctx, name, &value);
}
void __qmljs_get_property(Context *ctx, Value *result, Value *object, String *name)
void __qmljs_get_activation_property(Context *ctx, Value *result, String *name)
{
- __qmljs_get_property(ctx, result, &ctx->activation, name);
+ if (Value *prop = ctx->lookup(name))
+ *result = *prop;
+ else
+ assert(!"reference error");
}
void __qmljs_get_activation(Context *ctx, Value *result)
return false;
}
-Context *__qmljs_new_context(Context *current, Value *thisObject, size_t argc)
+void __qmljs_call_activation_property(Context *context, Value *result, String *name, Value *args, int argc)
{
- Context *ctx = new Context;
- ctx->init();
- 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 __qmljs_dispose_context(Context *ctx)
-{
- delete[] ctx->arguments;
- delete ctx;
-}
+ Value *func = context->lookup(name);
+ if (! func)
+ assert(!"reference error");
-void __qmljs_call_activation_property(Context *context, Value *result, String *name)
-{
- __qmljs_call_property(context, result, &context->parent->activation, name);
+ __qmljs_call_value(context, result, func, args, argc);
}
-void __qmljs_call_property(Context *context, Value *result, Value *base, String *name)
+void __qmljs_call_property(Context *context, Value *result, const Value *base, String *name, Value *args, int argc)
{
Value baseObject;
Value thisObject;
baseObject.objectValue->get(name, &func);
if (func.type == OBJECT_TYPE) {
if (FunctionObject *f = func.objectValue->asFunctionObject()) {
- context->thisObject = thisObject;
- context->formals = f->formalParameterList;
- context->formalCount = f->formalParameterCount;
- f->call(context);
+ Context *ctx = new Context;
+ ctx->init();
+ __qmljs_init_object(ctx, &ctx->activation, new ArgumentsObject(ctx));
+ ctx->parent = f->scope;
+ ctx->thisObject = thisObject;
+ ctx->formals = f->formalParameterList;
+ ctx->formalCount = f->formalParameterCount;
+ ctx->arguments = args;
+ ctx->argumentCount = argc;
+ f->call(ctx);
if (result)
- __qmljs_copy(result, &context->result);
+ __qmljs_copy(result, &ctx->result);
} else {
assert(!"not a function");
}
}
}
-void __qmljs_call_value(Context *context, Value *result, Value *func)
+void __qmljs_call_value(Context *context, Value *result, const Value *func, Value *args, int argc)
{
if (func->type == OBJECT_TYPE) {
if (FunctionObject *f = func->objectValue->asFunctionObject()) {
- __qmljs_init_null(context, &context->thisObject);
- context->formals = f->formalParameterList;
- context->formalCount = f->formalParameterCount;
- f->call(context);
+ Context *ctx = new Context;
+ ctx->init();
+ ctx->parent = f->scope;
+ __qmljs_init_object(ctx, &ctx->activation, new ArgumentsObject(ctx));
+ __qmljs_init_null(ctx, &ctx->thisObject);
+ ctx->formals = f->formalParameterList;
+ ctx->formalCount = f->formalParameterCount;
+ if (argc) {
+ ctx->arguments = new Value[argc];
+ std::copy(args, args + argc, ctx->arguments);
+ } else {
+ ctx->arguments = 0;
+ }
+ ctx->argumentCount = argc;
+ f->call(ctx);
if (result)
- __qmljs_copy(result, &context->result);
+ __qmljs_copy(result, &ctx->result);
} else {
assert(!"not a function");
}
}
}
-void __qmljs_construct_activation_property(Context *context, Value *result, String *name)
+void __qmljs_construct_activation_property(Context *context, Value *result, String *name, Value *args, int argc)
{
- __qmljs_construct_property(context, result, &context->activation, name);
+ Value *func = context->lookup(name);
+ if (! func)
+ assert(!"reference error");
+
+ __qmljs_construct_value(context, result, func, args, argc);
+}
+
+void __qmljs_construct_value(Context *context, Value *result, const Value *func, Value *args, int argc)
+{
+ if (func->type == OBJECT_TYPE) {
+ if (FunctionObject *f = func->objectValue->asFunctionObject()) {
+ Context *ctx = new Context;
+ ctx->init();
+ ctx->parent = f->scope;
+ __qmljs_init_null(ctx, &ctx->thisObject);
+ __qmljs_init_object(ctx, &ctx->activation, new ArgumentsObject(ctx));
+ ctx->formals = f->formalParameterList;
+ ctx->formalCount = f->formalParameterCount;
+ ctx->arguments = args;
+ ctx->argumentCount = argc;
+ ctx->calledAsConstructor = true;
+ f->construct(ctx);
+ assert(ctx->thisObject.is(OBJECT_TYPE));
+ ctx->result = ctx->thisObject;
+ Value proto;
+ if (f->get(String::get(ctx, QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
+ if (proto.type == OBJECT_TYPE)
+ ctx->thisObject.objectValue->prototype = proto.objectValue;
+ }
+
+ if (result)
+ __qmljs_copy(result, &ctx->thisObject);
+ } else {
+ assert(!"not a function");
+ }
+ } else {
+ assert(!"not a callable object");
+ }
}
-void __qmljs_construct_property(Context *context, Value *result, Value *base, String *name)
+void __qmljs_construct_property(Context *context, Value *result, const Value *base, String *name, Value *args, int argc)
{
Value func;
Value thisObject = *base;
thisObject.objectValue->get(name, &func);
if (func.type == OBJECT_TYPE) {
if (FunctionObject *f = func.objectValue->asFunctionObject()) {
- context->thisObject = thisObject;
- context->formals = f->formalParameterList;
- context->formalCount = f->formalParameterCount;
- context->calledAsConstructor = true;
- f->construct(context);
+ Context *ctx = new Context;
+ ctx->init();
+ ctx->parent = f->scope;
+ ctx->thisObject = thisObject;
+ __qmljs_init_object(ctx, &ctx->activation, new ArgumentsObject(ctx));
+ ctx->formals = f->formalParameterList;
+ ctx->formalCount = f->formalParameterCount;
+ ctx->calledAsConstructor = true;
+ ctx->arguments = args;
+ ctx->argumentCount = argc;
+ ctx->calledAsConstructor = true;
+ f->construct(ctx);
+ assert(ctx->thisObject.is(OBJECT_TYPE));
Value proto;
- if (f->get(String::get(context, QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
+ if (f->get(String::get(ctx, QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
if (proto.type == OBJECT_TYPE)
- context->thisObject.objectValue->prototype = proto.objectValue;
+ ctx->thisObject.objectValue->prototype = proto.objectValue;
}
if (result)
- __qmljs_copy(result, &context->thisObject);
+ __qmljs_copy(result, &ctx->thisObject);
} else {
assert(!"not a function");
}
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);
-void __qmljs_construct_activation_property(Context *, Value *result, String *name);
-void __qmljs_call_property(Context *context, Value *result, Value *base, String *name);
-void __qmljs_construct_property(Context *context, Value *result, Value *base, String *name);
-void __qmljs_call_value(Context *context, Value *result, Value *func);
+void __qmljs_call_activation_property(Context *, Value *result, String *name, Value *args, int argc);
+void __qmljs_call_property(Context *context, Value *result, const Value *base, String *name, Value *args, int argc);
+void __qmljs_call_value(Context *context, Value *result, const Value *func, Value *args, int argc);
+
+void __qmljs_construct_activation_property(Context *, Value *result, String *name, Value *args, int argc);
+void __qmljs_construct_property(Context *context, Value *result, const Value *base, String *name, Value *args, int argc);
+void __qmljs_construct_value(Context *context, Value *result, const Value *func, Value *args, int argc);
// constructors
void __qmljs_init_undefined(Context *ctx, Value *result);
// search for locals
QList<QStringRef> locals;
- bool directEval;
+ int maxNumberOfArguments;
+ bool hasDirectEval;
+ bool hasNestedFunctions;
ScanFunctionBody()
- : directEval(false)
+ : maxNumberOfArguments(0)
+ , hasDirectEval(false)
+ , hasNestedFunctions(false)
{
}
void operator()(Node *node) {
- directEval = false;
+ hasDirectEval = false;
locals.clear();
if (node)
node->accept(this);
protected:
virtual bool visit(CallExpression *ast)
{
- if (! directEval) {
+ if (! hasDirectEval) {
if (IdentifierExpression *id = cast<IdentifierExpression *>(ast->base)) {
if (id->name == QLatin1String("eval")) {
- directEval = true;
+ hasDirectEval = true;
}
}
}
+ int argc = 0;
+ for (AST::ArgumentList *it = ast->arguments; it; it = it->next)
+ ++argc;
+ maxNumberOfArguments = qMax(maxNumberOfArguments, argc);
+ return true;
+ }
+
+ virtual bool visit(NewMemberExpression *ast)
+ {
+ int argc = 0;
+ for (AST::ArgumentList *it = ast->arguments; it; it = it->next)
+ ++argc;
+ maxNumberOfArguments = qMax(maxNumberOfArguments, argc);
return true;
}
virtual bool visit(FunctionExpression *ast)
{
+ hasNestedFunctions = true;
if (! locals.contains(ast->name))
locals.append(ast->name);
return false;
virtual bool visit(FunctionDeclaration *ast)
{
+ hasNestedFunctions = true;
if (! locals.contains(ast->name))
locals.append(ast->name);
return false;
_module = module;
IR::Function *globalCode = _module->newFunction(QLatin1String("%entry"));
- globalCode->directEval = true; // ### remove
+ globalCode->hasDirectEval = true; // ### remove
+ globalCode->hasNestedFunctions = true; // ### remove
+ globalCode->redArea = 10; // ### remove
_function = globalCode;
_block = _function->newBasicBlock();
_exitBlock = _function->newBasicBlock();
return _block->BINOP(op, left, right);
}
+IR::Expr *Codegen::call(IR::Expr *base, IR::ExprList *args)
+{
+ if (base->asMember() || base->asName() || base->asTemp())
+ return _block->CALL(base, args);
+ const unsigned t = _block->newTemp();
+ _block->MOVE(_block->TEMP(t), base);
+ return _block->CALL(_block->TEMP(t), args);
+}
+
void Codegen::move(IR::Expr *target, IR::Expr *source, IR::AluOp op)
{
if (target->asMember()) {
if (! expr.code)
expr.code = _block->CONST(IR::UndefinedType, 0);
- if (! _function->directEval) {
+ if (! _function->needsActivation()) {
const int index = tempForLocalVariable(ast->name);
if (index != -1) {
move(_block->TEMP(index), *expr);
(*args_it)->init(actual);
args_it = &(*args_it)->next;
}
- _expr.code = _block->CALL(*base, args);
+ _expr.code = call(*base, args);
return false;
}
bool Codegen::visit(IdentifierExpression *ast)
{
- if (! _function->directEval) {
+ if (! _function->needsActivation()) {
int index = tempForLocalVariable(ast->name);
if (index != -1) {
_expr.code = _block->TEMP(index);
Result expr = expression(ast->expression);
IR::ExprList *args = _function->New<IR::ExprList>();
args->init(argument(*expr));
- _expr.code = _block->CALL(_block->NAME(QLatin1String("typeof"), ast->typeofToken.startLine, ast->typeofToken.startColumn), args);
+ _expr.code = call(_block->NAME(QLatin1String("typeof"), ast->typeofToken.startLine, ast->typeofToken.startColumn), args);
return false;
}
IR::Function *function = _module->newFunction(ast->name.toString());
IR::BasicBlock *entryBlock = function->newBasicBlock();
IR::BasicBlock *exitBlock = function->newBasicBlock();
+ function->hasDirectEval = functionInfo.hasDirectEval;
+ function->redArea = functionInfo.maxNumberOfArguments;
- if (! functionInfo.directEval) {
+ if (! functionInfo.hasDirectEval) {
for (int i = 0; i < functionInfo.locals.size(); ++i) {
unsigned t = entryBlock->newTemp();
Q_ASSERT(t == unsigned(i));
IR::Expr *subscript(IR::Expr *base, IR::Expr *index);
IR::Expr *argument(IR::Expr *expr);
IR::Expr *binop(IR::AluOp op, IR::Expr *left, IR::Expr *right);
+ IR::Expr *call(IR::Expr *base, IR::ExprList *args);
void move(IR::Expr *target, IR::Expr *source, IR::AluOp op = IR::OpInvalid);
void linearize(IR::Function *function);
const QString *name;
QVector<BasicBlock *> basicBlocks;
int tempCount;
+ int redArea;
QSet<QString> strings;
QList<const QString *> formals;
QList<const QString *> locals;
void (*code)(VM::Context *);
- bool directEval;
+ bool hasDirectEval: 1;
+ bool hasNestedFunctions: 1;
template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
: module(module)
, pool(&module->pool)
, tempCount(0)
+ , redArea(0)
, code(0)
- , directEval(false)
+ , hasDirectEval(false)
+ , hasNestedFunctions(false)
{ this->name = newString(name); }
~Function();
inline BasicBlock *i(BasicBlock *block) { basicBlocks.append(block); return block; }
void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
+
+ inline bool needsActivation() const { return hasNestedFunctions || hasDirectEval; }
};
struct BasicBlock {
function->code = (void (*)(VM::Context *)) _code;
_codePtr = _code;
- int locals = function->tempCount * sizeof(Value);
+ int locals = (function->tempCount + function->redArea) * sizeof(Value);
locals = (locals + 15) & ~15;
amd64_push_reg(_codePtr, AMD64_RBP);
assert(baseName != 0);
int argc = 0;
- for (IR::ExprList *it = call->args; it; it = it->next)
+ 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);
+ int i = 0;
+ for (IR::ExprList *it = call->args; it; it = it->next, ++i) {
+ IR::Temp *arg = it->expr->asTemp();
+ assert(arg != 0);
+ amd64_lea_membase(_codePtr, AMD64_RDI, AMD64_RSP, sizeof(Value) * i);
+ loadTempAddress(AMD64_RSI, arg);
amd64_call_code(_codePtr, __qmljs_copy);
- ++argc;
}
- String *id = identifier(*baseName->id);
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8); // load the context
+
if (result)
loadTempAddress(AMD64_RSI, result);
else
amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_RSI, AMD64_RSI);
- amd64_mov_reg_imm(_codePtr, AMD64_RDX, id);
+
+ amd64_mov_reg_imm(_codePtr, AMD64_RDX, identifier(*baseName->id));
+ amd64_lea_membase(_codePtr, AMD64_RCX, AMD64_RSP, 0);
+ amd64_mov_reg_imm(_codePtr, AMD64_R8, argc);
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);
}
assert(baseTemp != 0);
int argc = 0;
- for (IR::ExprList *it = call->args; it; it = it->next)
+ 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);
+ int i = 0;
+ for (IR::ExprList *it = call->args; it; it = it->next, ++i) {
+ IR::Temp *arg = it->expr->asTemp();
+ assert(arg != 0);
+ amd64_lea_membase(_codePtr, AMD64_RDI, AMD64_RSP, sizeof(Value) * i);
+ loadTempAddress(AMD64_RSI, arg);
amd64_call_code(_codePtr, __qmljs_copy);
- ++argc;
}
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8); // load the context
+
if (result)
loadTempAddress(AMD64_RSI, result);
else
amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_RSI, AMD64_RSI);
+
loadTempAddress(AMD64_RDX, baseTemp);
+ amd64_lea_membase(_codePtr, AMD64_RCX, AMD64_RSP, 0);
+ amd64_mov_reg_imm(_codePtr, AMD64_R8, argc);
amd64_call_code(_codePtr, __qmljs_call_value);
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
- amd64_call_code(_codePtr, __qmljs_dispose_context);
}
void InstructionSelection::callProperty(IR::Call *call, IR::Temp *result)
assert(member->base->asTemp());
int argc = 0;
- for (IR::ExprList *it = call->args; it; it = it->next)
+ 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);
+ int i = 0;
+ for (IR::ExprList *it = call->args; it; it = it->next, ++i) {
+ IR::Temp *arg = it->expr->asTemp();
+ assert(arg != 0);
+ amd64_lea_membase(_codePtr, AMD64_RDI, AMD64_RSP, sizeof(Value) * i);
+ loadTempAddress(AMD64_RSI, arg);
amd64_call_code(_codePtr, __qmljs_copy);
- ++argc;
}
- // __qmljs_call_property(Context *context, Value *result, Value *base, String *name)
+ //__qmljs_call_property(ctx, result, base, name, args, argc);
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8); // load the context
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
if (result)
loadTempAddress(AMD64_RSI, result);
else
amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_RSI, AMD64_RSI);
+
loadTempAddress(AMD64_RDX, member->base->asTemp());
amd64_mov_reg_imm(_codePtr, AMD64_RCX, identifier(*member->name));
+ amd64_lea_membase(_codePtr, AMD64_R8, AMD64_RSP, 0);
+ amd64_mov_reg_imm(_codePtr, AMD64_R9, argc);
amd64_call_code(_codePtr, __qmljs_call_property);
-
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
- amd64_call_code(_codePtr, __qmljs_dispose_context);
}
void InstructionSelection::constructActivationProperty(IR::New *call, IR::Temp *result)
{
+ IR::Name *baseName = call->base->asName();
+ assert(baseName != 0);
+
int argc = 0;
- for (IR::ExprList *it = call->args; it; it = it->next)
+ 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);
+ int i = 0;
+ for (IR::ExprList *it = call->args; it; it = it->next, ++i) {
+ IR::Temp *arg = it->expr->asTemp();
+ assert(arg != 0);
+ amd64_lea_membase(_codePtr, AMD64_RDI, AMD64_RSP, sizeof(Value) * i);
+ loadTempAddress(AMD64_RSI, arg);
amd64_call_code(_codePtr, __qmljs_copy);
- ++argc;
}
- String *id = identifier(*call->base->asName()->id);
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8); // load the context
+
if (result)
loadTempAddress(AMD64_RSI, result);
else
amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_RSI, AMD64_RSI);
- amd64_mov_reg_imm(_codePtr, AMD64_RDX, id);
+
+ amd64_mov_reg_imm(_codePtr, AMD64_RDX, identifier(*baseName->id));
+ amd64_lea_membase(_codePtr, AMD64_RCX, AMD64_RSP, 0);
+ amd64_mov_reg_imm(_codePtr, AMD64_R8, argc);
amd64_call_code(_codePtr, __qmljs_construct_activation_property);
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
- amd64_call_code(_codePtr, __qmljs_dispose_context);
}
-void InstructionSelection::constructProperty(IR::New *ctor, IR::Temp *result)
+void InstructionSelection::constructProperty(IR::New *call, IR::Temp *result)
{
- IR::Member *member = ctor->base->asMember();
+ IR::Member *member = call->base->asMember();
assert(member != 0);
assert(member->base->asTemp());
int argc = 0;
- for (IR::ExprList *it = ctor->args; it; it = it->next)
+ 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 = ctor->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);
+ int i = 0;
+ for (IR::ExprList *it = call->args; it; it = it->next, ++i) {
+ IR::Temp *arg = it->expr->asTemp();
+ assert(arg != 0);
+ amd64_lea_membase(_codePtr, AMD64_RDI, AMD64_RSP, sizeof(Value) * i);
+ loadTempAddress(AMD64_RSI, arg);
amd64_call_code(_codePtr, __qmljs_copy);
- ++argc;
}
- // __qmljs_construct_property(Context *context, Value *result, Value *base, String *name)
+ //__qmljs_call_property(ctx, result, base, name, args, argc);
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8); // load the context
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
if (result)
loadTempAddress(AMD64_RSI, result);
else
amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_RSI, AMD64_RSI);
+
loadTempAddress(AMD64_RDX, member->base->asTemp());
amd64_mov_reg_imm(_codePtr, AMD64_RCX, identifier(*member->name));
+ amd64_lea_membase(_codePtr, AMD64_R8, AMD64_RSP, 0);
+ amd64_mov_reg_imm(_codePtr, AMD64_R9, argc);
amd64_call_code(_codePtr, __qmljs_construct_property);
-
- amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
- amd64_call_code(_codePtr, __qmljs_dispose_context);
}
void InstructionSelection::visitExp(IR::Exp *s)
--- /dev/null
+
+function fix(f) {
+ var k = function (x) {
+ return f(function (z) { return x(x)(z) })
+ }
+ return k(k)
+}
+
+var F = function (f) {
+ return function (n) {
+ return n == 0 ? 1 : n * f(n - 1)
+ }
+}
+
+var fact = fix(F)
+
+print("the factorial of 12 is", fact(12))