From a97bc91c7f3d08595245a88247776a7fb6c6516e Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Sun, 13 May 2012 13:50:55 +0200 Subject: [PATCH] Fix nested functions --- main.cpp | 16 +++-- qmljs_objects.cpp | 7 +-- qmljs_objects.h | 19 +++--- qmljs_runtime.cpp | 178 +++++++++++++++++++++++++++++++++++------------------ qmljs_runtime.h | 14 ++--- qv4codegen.cpp | 54 ++++++++++++---- qv4codegen_p.h | 1 + qv4ir_p.h | 10 ++- qv4isel.cpp | 179 ++++++++++++++++++++++-------------------------------- tests/fun.3.js | 17 ++++++ 10 files changed, 295 insertions(+), 200 deletions(-) create mode 100644 tests/fun.3.js diff --git a/main.cpp b/main.cpp index 8077479..1bf71b4 100644 --- a/main.cpp +++ b/main.cpp @@ -28,6 +28,8 @@ 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) { @@ -43,9 +45,11 @@ struct Print: FunctionObject 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 *) @@ -56,6 +60,8 @@ struct ObjectCtor: FunctionObject struct StringCtor: FunctionObject { + StringCtor(Context *scope): FunctionObject(scope) {} + virtual void construct(Context *ctx) { Value arg = ctx->argument(0); @@ -88,7 +94,7 @@ struct StringPrototype: Object 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) @@ -147,12 +153,12 @@ void evaluate(QQmlJS::Engine *engine, const QString &fileName, const QString &co __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)); diff --git a/qmljs_objects.cpp b/qmljs_objects.cpp index 7a37351..a1a97e5 100644 --- a/qmljs_objects.cpp +++ b/qmljs_objects.cpp @@ -118,8 +118,8 @@ void FunctionObject::construct(Context *ctx) 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(); @@ -143,6 +143,7 @@ void ScriptFunction::call(VM::Context *ctx) void ScriptFunction::construct(VM::Context *ctx) { + __qmljs_init_object(ctx, &ctx->thisObject, new Object()); function->code(ctx); } @@ -160,7 +161,5 @@ Value *ArgumentsObject::getProperty(String *name, PropertyAttributes *attributes } if (Value *prop = Object::getProperty(name, attributes)) return prop; - else if (context && context->scope) - return context->scope->getProperty(name, attributes); return 0; } diff --git a/qmljs_objects.h b/qmljs_objects.h index 323367a..5631b7d 100644 --- a/qmljs_objects.h +++ b/qmljs_objects.h @@ -233,11 +233,11 @@ struct ArrayObject: Object { }; 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; @@ -248,16 +248,15 @@ struct FunctionObject: Object { 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); @@ -279,7 +278,6 @@ struct Context { Context *parent; Value activation; Value thisObject; - Object *scope; Value *arguments; size_t argumentCount; Value result; @@ -287,6 +285,14 @@ struct Context { 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; @@ -305,7 +311,6 @@ struct Context { void init() { parent = 0; - scope = 0; arguments = 0; argumentCount = 0; activation.type = NULL_TYPE; diff --git a/qmljs_runtime.cpp b/qmljs_runtime.cpp index b0a3c10..0f75105 100644 --- a/qmljs_runtime.cpp +++ b/qmljs_runtime.cpp @@ -1,6 +1,7 @@ #include "qmljs_runtime.h" #include "qmljs_objects.h" +#include "qv4ir_p.h" #include #include #include @@ -200,38 +201,52 @@ void __qmljs_set_property_string(Context *ctx, Value *object, String *name, Stri 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) @@ -248,7 +263,10 @@ void __qmljs_get_property(Context *ctx, Value *result, Value *object, String *na 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) @@ -349,34 +367,16 @@ bool __qmljs_equal(Context *ctx, const Value *x, const Value *y) 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; @@ -394,12 +394,18 @@ void __qmljs_call_property(Context *context, Value *result, Value *base, String 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"); } @@ -408,16 +414,27 @@ void __qmljs_call_property(Context *context, Value *result, Value *base, String } } -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"); } @@ -426,12 +443,49 @@ void __qmljs_call_value(Context *context, Value *result, Value *func) } } -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; @@ -442,20 +496,28 @@ void __qmljs_construct_property(Context *context, Value *result, Value *base, St 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"); } diff --git a/qmljs_runtime.h b/qmljs_runtime.h index c75e502..143319e 100644 --- a/qmljs_runtime.h +++ b/qmljs_runtime.h @@ -44,13 +44,13 @@ struct Context; 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); diff --git a/qv4codegen.cpp b/qv4codegen.cpp index 2bc9dbd..221ab5e 100644 --- a/qv4codegen.cpp +++ b/qv4codegen.cpp @@ -159,15 +159,19 @@ struct ScanFunctionBody: Visitor // search for locals QList 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); @@ -176,13 +180,26 @@ struct ScanFunctionBody: Visitor protected: virtual bool visit(CallExpression *ast) { - if (! directEval) { + if (! hasDirectEval) { if (IdentifierExpression *id = cast(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; } @@ -195,6 +212,7 @@ protected: virtual bool visit(FunctionExpression *ast) { + hasNestedFunctions = true; if (! locals.contains(ast->name)) locals.append(ast->name); return false; @@ -202,6 +220,7 @@ protected: virtual bool visit(FunctionDeclaration *ast) { + hasNestedFunctions = true; if (! locals.contains(ast->name)) locals.append(ast->name); return false; @@ -223,7 +242,9 @@ void Codegen::operator()(AST::Program *node, IR::Module *module) _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(); @@ -291,6 +312,15 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right) 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()) { @@ -519,7 +549,7 @@ void Codegen::variableDeclaration(VariableDeclaration *ast) 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); @@ -895,7 +925,7 @@ bool Codegen::visit(CallExpression *ast) (*args_it)->init(actual); args_it = &(*args_it)->next; } - _expr.code = _block->CALL(*base, args); + _expr.code = call(*base, args); return false; } @@ -951,7 +981,7 @@ bool Codegen::visit(FunctionExpression *ast) bool Codegen::visit(IdentifierExpression *ast) { - if (! _function->directEval) { + if (! _function->needsActivation()) { int index = tempForLocalVariable(ast->name); if (index != -1) { _expr.code = _block->TEMP(index); @@ -1121,7 +1151,7 @@ bool Codegen::visit(TypeOfExpression *ast) Result expr = expression(ast->expression); IR::ExprList *args = _function->New(); 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; } @@ -1308,8 +1338,10 @@ void Codegen::defineFunction(FunctionExpression *ast, bool /*isDeclaration*/) 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)); diff --git a/qv4codegen_p.h b/qv4codegen_p.h index e58ceb5..63c12c3 100644 --- a/qv4codegen_p.h +++ b/qv4codegen_p.h @@ -71,6 +71,7 @@ protected: 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); diff --git a/qv4ir_p.h b/qv4ir_p.h index a77a58f..57fe54b 100644 --- a/qv4ir_p.h +++ b/qv4ir_p.h @@ -587,11 +587,13 @@ struct Function { const QString *name; QVector basicBlocks; int tempCount; + int redArea; QSet strings; QList formals; QList locals; void (*code)(VM::Context *); - bool directEval; + bool hasDirectEval: 1; + bool hasNestedFunctions: 1; template _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); } @@ -599,8 +601,10 @@ struct Function { : module(module) , pool(&module->pool) , tempCount(0) + , redArea(0) , code(0) - , directEval(false) + , hasDirectEval(false) + , hasNestedFunctions(false) { this->name = newString(name); } ~Function(); @@ -614,6 +618,8 @@ struct 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 { diff --git a/qv4isel.cpp b/qv4isel.cpp index a689bec..c53741b 100644 --- a/qv4isel.cpp +++ b/qv4isel.cpp @@ -101,7 +101,7 @@ void InstructionSelection::operator()(IR::Function *function) 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); @@ -179,37 +179,30 @@ void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *resu 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); } @@ -219,36 +212,30 @@ void InstructionSelection::callValue(IR::Call *call, IR::Temp *result) 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) @@ -258,119 +245,99 @@ 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) diff --git a/tests/fun.3.js b/tests/fun.3.js new file mode 100644 index 0000000..5add270 --- /dev/null +++ b/tests/fun.3.js @@ -0,0 +1,17 @@ + +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)) -- 2.7.4