checkpoint
authorRoberto Raggi <roberto.raggi@nokia.com>
Wed, 16 May 2012 09:58:07 +0000 (11:58 +0200)
committerRoberto Raggi <roberto.raggi@nokia.com>
Wed, 16 May 2012 09:58:07 +0000 (11:58 +0200)
qmljs_objects.cpp
qmljs_objects.h
qmljs_runtime.cpp
qv4codegen.cpp
qv4codegen_p.h
qv4ir.cpp
qv4ir_p.h
qv4isel.cpp

index 3192ac9..011b39c 100644 (file)
@@ -140,11 +140,20 @@ ScriptFunction::ScriptFunction(Context *scope, IR::Function *function)
             formalParameterList[i] = scope->engine->identifier(*function->formals.at(i));
         }
     }
+
+    varCount = function->locals.size();
+    if (varCount) {
+        varList = new String*[varCount];
+        for (size_t i = 0; i < varCount; ++i) {
+            varList[i] = scope->engine->identifier(*function->locals.at(i));
+        }
+    }
 }
 
 ScriptFunction::~ScriptFunction()
 {
     delete[] formalParameterList;
+    delete[] varList;
 }
 
 void ScriptFunction::call(VM::Context *ctx)
@@ -161,6 +170,14 @@ void ScriptFunction::construct(VM::Context *ctx)
 Value *ArgumentsObject::getProperty(String *name, PropertyAttributes *attributes)
 {
     if (context) {
+        for (size_t i = 0; i < context->varCount; ++i) {
+            String *var = context->vars[i];
+            if (__qmljs_string_equal(context, var, name)) {
+                if (attributes)
+                    *attributes = PropertyAttributes(*attributes | WritableAttribute);
+                return &context->locals[i];
+            }
+        }
         for (size_t i = 0; i < context->formalCount; ++i) {
             String *formal = context->formals[i];
             if (__qmljs_string_equal(context, formal, name)) {
index ebc3cd0..fdb0b98 100644 (file)
@@ -239,12 +239,16 @@ struct FunctionObject: Object {
     Context *scope;
     String **formalParameterList;
     size_t formalParameterCount;
+    String **varList;
+    size_t varCount;
     bool needsActivation;
 
     FunctionObject(Context *scope)
         : scope(scope)
         , formalParameterList(0)
         , formalParameterCount(0)
+        , varList(0)
+        , varCount(0)
         , needsActivation(true) {}
     virtual FunctionObject *asFunctionObject() { return this; }
 
@@ -289,15 +293,19 @@ struct Context {
     Value thisObject;
     Value *arguments;
     size_t argumentCount;
+    Value *locals;
     Value result;
     String **formals;
     size_t formalCount;
+    String **vars;
+    size_t varCount;
     bool calledAsConstructor;
 
     Value *lookup(String *name) {
         if (activation.is(OBJECT_TYPE)) {
-            if (Value *prop = activation.objectValue->getProperty(name))
+            if (Value *prop = activation.objectValue->getProperty(name)) {
                 return prop;
+            }
         }
         return parent ? parent->lookup(name) : 0;
     }
@@ -323,11 +331,14 @@ struct Context {
         parent = 0;
         arguments = 0;
         argumentCount = 0;
+        locals = 0;
         activation.type = NULL_TYPE;
         thisObject.type = NULL_TYPE;
         result.type = UNDEFINED_TYPE;
         formals = 0;
         formalCount = 0;
+        vars = 0;
+        varCount = 0;
         calledAsConstructor = false;
     }
 };
index 572928b..e52ef24 100644 (file)
@@ -504,6 +504,9 @@ void __qmljs_call_value(Context *context, Value *result, const Value *func, Valu
                 ctx->arguments = new Value[argc];
                 std::copy(args, args + argc, ctx->arguments);
             }
+            ctx->vars = f->varList;
+            ctx->varCount = f->varCount;
+            ctx->locals = 0;
             f->call(ctx);
             if (result)
                 __qmljs_copy(result, &ctx->result);
index 608eba8..97b004b 100644 (file)
@@ -158,25 +158,33 @@ void liveness(IR::Function *function)
     } while (changed);
 }
 
-struct ScanFunctionBody: Visitor
+} // end of anonymous namespace
+
+struct Codegen::ScanFunctionBody: Visitor
 {
     using Visitor::visit;
 
     // search for locals
+    Codegen::Environment *env;
     QList<QStringRef> locals;
     int maxNumberOfArguments;
     bool hasDirectEval;
     bool hasNestedFunctions;
 
     ScanFunctionBody()
-        : maxNumberOfArguments(0)
+        : env(0)
+        , maxNumberOfArguments(0)
         , hasDirectEval(false)
         , hasNestedFunctions(false)
     {
     }
 
-    void operator()(Node *node) {
+    void operator()(Node *node, Environment *e)
+    {
+        env = e;
+        maxNumberOfArguments = 0;
         hasDirectEval = false;
+        hasNestedFunctions = false;
         locals.clear();
         if (node)
             node->accept(this);
@@ -210,6 +218,7 @@ protected:
 
     virtual bool visit(VariableDeclaration *ast)
     {
+        env->enter(ast->name);
         if (! locals.contains(ast->name))
             locals.append(ast->name);
         return true;
@@ -217,6 +226,7 @@ protected:
 
     virtual bool visit(FunctionExpression *ast)
     {
+        env->enter(ast->name);
         hasNestedFunctions = true;
         if (! locals.contains(ast->name))
             locals.append(ast->name);
@@ -225,6 +235,7 @@ protected:
 
     virtual bool visit(FunctionDeclaration *ast)
     {
+        env->enter(ast->name);
         hasNestedFunctions = true;
         if (! locals.contains(ast->name))
             locals.append(ast->name);
@@ -232,13 +243,13 @@ protected:
     }
 };
 
-} // end of anonymous namespace
-
 Codegen::Codegen()
-    : _function(0)
+    : _module(0)
+    , _function(0)
     , _block(0)
     , _exitBlock(0)
     , _returnAddress(0)
+    , _env(0)
 {
 }
 
@@ -246,8 +257,9 @@ void Codegen::operator()(AST::Program *node, IR::Module *module)
 {
     _module = module;
 
+    Scope scope(this, newEnvironment());
     ScanFunctionBody globalCodeInfo;
-    globalCodeInfo(node);
+    globalCodeInfo(node, _env);
 
     IR::Function *globalCode = _module->newFunction(QLatin1String("%entry"));
     globalCode->hasDirectEval = globalCodeInfo.hasDirectEval;
@@ -269,6 +281,9 @@ void Codegen::operator()(AST::Program *node, IR::Module *module)
     foreach (IR::Function *function, _module->functions) {
         linearize(function);
     }
+
+    qDeleteAll(_allEnvironments);
+    _allEnvironments.clear();
 }
 
 IR::Expr *Codegen::member(IR::Expr *base, const QString *name)
@@ -568,6 +583,7 @@ void Codegen::variableDeclaration(VariableDeclaration *ast)
                 move(_block->TEMP(-(index + 1)), *expr);
                 return;
             }
+            Q_UNREACHABLE();
         } else {
             move(_block->NAME(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn), *expr);
         }
@@ -1252,7 +1268,9 @@ void Codegen::linearize(IR::Function *function)
     trace.append(exitBlock);
     function->basicBlocks = trace;
 
+#ifndef QV4_NO_LIVENESS
     liveness(function);
+#endif
 
     static bool showCode = !qgetenv("SHOW_CODE").isNull();
     if (showCode) {
@@ -1304,6 +1322,7 @@ void Codegen::linearize(IR::Function *function)
             s->dump(out, IR::Stmt::MIR);
             out.flush();
 
+#ifndef QV4_NO_LIVENESS
             for (int i = 60 - str.size(); i >= 0; --i)
                 str.append(' ');
 
@@ -1330,6 +1349,9 @@ void Codegen::linearize(IR::Function *function)
                         qout << " %" << i;
                 }
             }
+#else
+            qout << "    " << str;
+#endif
 
             qout << endl;
 
@@ -1342,16 +1364,19 @@ void Codegen::linearize(IR::Function *function)
              << endl;
     }
 
+#ifndef QV4_NO_LIVENESS
     foreach (IR::BasicBlock *block, function->basicBlocks) {
         foreach (IR::Stmt *s, block->statements)
             s->destroyData();
     }
+#endif
 }
 
 void Codegen::defineFunction(FunctionExpression *ast, bool /*isDeclaration*/)
 {
+    Scope scope(this, newEnvironment());
     ScanFunctionBody functionInfo;
-    functionInfo(ast->body);
+    functionInfo(ast->body, _env);
 
     IR::Function *function = _module->newFunction(ast->name.toString());
     IR::BasicBlock *entryBlock = function->newBasicBlock();
index 61ef851..92afa90 100644 (file)
@@ -53,6 +53,65 @@ protected:
         }
     };
 
+    struct Environment {
+        Environment *parent;
+        QHash<QStringRef, int> members;
+        int count;
+
+        Environment(Environment *parent = 0)
+            : parent(parent)
+            , count(0) {}
+
+        int findMember(const QStringRef &name) const
+        {
+            return members.value(name, -1);
+        }
+
+        bool lookupMember(const QStringRef &name, Environment **scope, int *index, int *distance)
+        {
+            Environment *it = this;
+            *distance = 0;
+            for (; it; it = it->parent, ++(*distance)) {
+                int idx = it->findMember(name);
+                if (idx != -1) {
+                    *scope = it;
+                    *index = idx;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        void enter(const QStringRef &name)
+        {
+            int idx = members.value(name, -1);
+            if (idx == -1)
+                members.insert(name, count++);
+        }
+    };
+
+    Environment *newEnvironment()
+    {
+        Environment *scope = new Environment(_env);
+        return scope;
+    }
+
+    Environment *changeEnvironment(Environment *env)
+    {
+        qSwap(_env, env);
+        return env;
+    }
+
+    struct Scope {
+        Codegen *cg;
+        Environment *previous;
+        inline Scope(Codegen *cg, Environment *env) { previous = cg->changeEnvironment(env); }
+        inline ~Scope() { cg->changeEnvironment(previous); }
+
+    private:
+        Q_DISABLE_COPY(Scope)
+    };
+
     struct UiMember {
     };
 
@@ -225,6 +284,10 @@ private:
     IR::BasicBlock *_block;
     IR::BasicBlock *_exitBlock;
     unsigned _returnAddress;
+    QVector<Environment *> _allEnvironments;
+    Environment *_env;
+
+    struct ScanFunctionBody;
 };
 
 } // end of namespace QQmlJS
index 0ea0b4d..6bcf6b5 100644 (file)
--- a/qv4ir.cpp
+++ b/qv4ir.cpp
@@ -241,10 +241,11 @@ void Name::dump(QTextStream &out)
 
 void Temp::dump(QTextStream &out)
 {
-    if (index < 0)
+    if (index < 0) {
         out << '#' << -(index + 1); // negative and 1-based.
-    else
+    } else {
         out << '%' << index; // temp
+    }
 }
 
 void Closure::dump(QTextStream &out)
@@ -496,7 +497,7 @@ unsigned BasicBlock::newTemp()
     return function->tempCount++;
 }
 
-Temp *BasicBlock::TEMP(unsigned index)
+Temp *BasicBlock::TEMP(int index)
 { 
     Temp *e = function->New<Temp>();
     e->init(IR::InvalidType, index);
index 594077a..e65b52a 100644 (file)
--- a/qv4ir_p.h
+++ b/qv4ir_p.h
@@ -655,7 +655,7 @@ struct BasicBlock {
 
     unsigned newTemp();
 
-    Temp *TEMP(unsigned index);
+    Temp *TEMP(int index);
 
     Expr *CONST(Type type, double value);
     Expr *STRING(const QString *value);
index 3e8d27a..b50dd83 100644 (file)
@@ -97,12 +97,14 @@ InstructionSelection::~InstructionSelection()
 
 void InstructionSelection::operator()(IR::Function *function)
 {
+    qSwap(_function, function);
+
     _code = _codePtr;
     _code = (uchar *) ((size_t(_code) + 15) & ~15);
-    function->code = (void (*)(VM::Context *)) _code;
+    _function->code = (void (*)(VM::Context *)) _code;
     _codePtr = _code;
 
-    int locals = (function->tempCount + function->maxNumberOfArguments) * sizeof(Value);
+    int locals = (_function->tempCount + _function->maxNumberOfArguments) * sizeof(Value);
     locals = (locals + 15) & ~15;
 
     amd64_push_reg(_codePtr, AMD64_RBP);
@@ -115,7 +117,11 @@ void InstructionSelection::operator()(IR::Function *function)
 
     amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_R15, AMD64_R15);
 
-    foreach (IR::BasicBlock *block, function->basicBlocks) {
+    amd64_lea_membase(_codePtr, AMD64_RAX, AMD64_RSP, _function->maxNumberOfArguments * sizeof(Value));
+    amd64_mov_membase_reg(_codePtr, AMD64_R14, offsetof(Context, locals), AMD64_RAX, 8);
+
+
+    foreach (IR::BasicBlock *block, _function->basicBlocks) {
         _block = block;
         _addrs[block] = _codePtr;
         foreach (IR::Stmt *s, block->statements) {
@@ -154,6 +160,7 @@ void InstructionSelection::operator()(IR::Function *function)
         }
     }
 #endif
+    qSwap(_function, _function);
 }
 
 String *InstructionSelection::identifier(const QString &s)
@@ -168,7 +175,7 @@ void InstructionSelection::loadTempAddress(int reg, IR::Temp *t)
         amd64_mov_reg_membase(_codePtr, reg, AMD64_R14, offsetof(Context, arguments), 8);
         amd64_lea_membase(_codePtr, reg, reg, sizeof(Value) * arg);
     } else {
-        amd64_lea_membase(_codePtr, reg, AMD64_RBP, sizeof(Value) * -t->index);
+        amd64_lea_membase(_codePtr, reg, AMD64_RSP, sizeof(Value) * (_function->maxNumberOfArguments + t->index));
     }
 }