Correctly set up nested functions
authorLars Knoll <lars.knoll@digia.com>
Thu, 13 Dec 2012 11:09:04 +0000 (12:09 +0100)
committerSimon Hausmann <simon.hausmann@digia.com>
Thu, 13 Dec 2012 11:38:11 +0000 (12:38 +0100)
Make sure we have the correct set of nested functions in
both IR::Function and VM::Function. This is required so
that closures can work correctly.

Change-Id: I42493d5ee503090653b71650c8d19e06c4bcfdda
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
moth/qv4isel_moth.cpp
moth/qv4isel_moth_p.h
qmljs_objects.cpp
qv4codegen.cpp
qv4ecmaobjects.cpp
qv4ir.cpp
qv4ir_p.h
qv4isel_masm.cpp
qv4isel_masm_p.h
qv4isel_p.cpp
qv4isel_p.h

index 5b00ccf..14fd1cb 100644 (file)
@@ -194,12 +194,24 @@ InstructionSelection::~InstructionSelection()
 {
 }
 
-VM::Function *InstructionSelection::run(IR::Function *function)
+void InstructionSelection::run(VM::Function *vmFunction, IR::Function *function)
 {
     qSwap(_function, function);
+
+    IR::BasicBlock *block;
+
+    QHash<IR::BasicBlock *, QVector<ptrdiff_t> > patches;
+    QHash<IR::BasicBlock *, ptrdiff_t> addrs;
+
     // FIXME: make the size dynamic. This requires changing the patching.
-    _code = new uchar[getpagesize() * 4000];
-    _ccode = _code;
+    uchar *code = new uchar[getpagesize() * 4000];
+    uchar *ccode = code;
+
+    qSwap(block, _block);
+    qSwap(patches, _patches);
+    qSwap(addrs, _addrs);
+    qSwap(code, _code);
+    qSwap(ccode, _ccode);
 
     CompressTemps().run(_function);
 
@@ -235,14 +247,14 @@ VM::Function *InstructionSelection::run(IR::Function *function)
     _patches.clear();
     _addrs.clear();
 
-    VM::Function *vmFunc = vmFunction(function);
-    vmFunc->code = VME::exec;
-    vmFunc->codeData = _code;
+    vmFunction->code = VME::exec;
+    vmFunction->codeData = _code;
 
-    _block = 0;
-    _code = 0;
-    _ccode = 0;
-    return vmFunc;
+    qSwap(block, _block);
+    qSwap(patches, _patches);
+    qSwap(addrs, _addrs);
+    qSwap(code, _code);
+    qSwap(ccode, _ccode);
 }
 
 void InstructionSelection::callActivationProperty(IR::Call *c, int targetTempIndex)
index e7c8517..dece413 100644 (file)
@@ -15,7 +15,7 @@ public:
     InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module);
     ~InstructionSelection();
 
-    virtual VM::Function *run(IR::Function *function);
+    virtual void run(VM::Function *vmFunction, IR::Function *function);
 
 protected:
     virtual void visitExp(IR::Exp *);
index 8ab6e50..b282332 100644 (file)
@@ -671,17 +671,8 @@ QQmlJS::VM::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ct
             Codegen cg(ctx);
             IR::Function *globalIRCode = cg(fileName, program, &module, mode);
             QScopedPointer<EvalInstructionSelection> isel(ctx->engine->iselFactory->create(vm, &module));
-            if (globalIRCode) {
-                globalCode = isel->run(globalIRCode);
-            }
-            if (globalCode) {
-                // only generate other functions if global code generation succeeded.
-                foreach (IR::Function *function, module.functions) {
-                    if (function == globalIRCode)
-                        continue;
-                    globalCode->nestedFunctions.append(isel->run(function));
-                }
-            }
+            if (globalIRCode)
+                globalCode = isel->vmFunction(globalIRCode);
         }
 
         if (! globalCode)
index 7409a54..1cbdc84 100644 (file)
@@ -1650,14 +1650,14 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
     TryCleanup *tryCleanup = 0;
 
     enterEnvironment(ast);
-    IR::Function *function = _module->newFunction(name);
+    IR::Function *function = _module->newFunction(name, _function);
+
     if (_debugger)
         _debugger->addFunction(function);
     IR::BasicBlock *entryBlock = function->newBasicBlock();
     IR::BasicBlock *exitBlock = function->newBasicBlock(IR::Function::DontInsertBlock);
     IR::BasicBlock *throwBlock = function->newBasicBlock();
     function->hasDirectEval = _env->hasDirectEval;
-    function->hasNestedFunctions = _env->hasNestedFunctions;
     function->maxNumberOfArguments = _env->maxNumberOfArguments;
     function->isStrict = _env->isStrict;
 
index 1a95c14..6bf661c 100644 (file)
@@ -2058,7 +2058,7 @@ Value FunctionCtor::construct(ExecutionContext *ctx)
     IR::Function *irf = cg(QString(), fe, &module);
 
     QScopedPointer<EvalInstructionSelection> isel(ctx->engine->iselFactory->create(ctx->engine, &module));
-    VM::Function *vmf = isel->run(irf);
+    VM::Function *vmf = isel->vmFunction(irf);
 
     ctx->thisObject = Value::fromObject(ctx->engine->newScriptFunction(ctx->engine->rootContext, vmf));
     return ctx->thisObject;
index 33b8b77..8d4c4f8 100644 (file)
--- a/qv4ir.cpp
+++ b/qv4ir.cpp
@@ -386,10 +386,16 @@ void Ret::dump(QTextStream &out, Mode)
     out << ';';
 }
 
-Function *Module::newFunction(const QString &name)
+Function *Module::newFunction(const QString &name, Function *outer)
 {
     Function *f = new Function(this, name);
     functions.append(f);
+    if (!outer) {
+        assert(!rootFunction);
+        rootFunction = f;
+    } else {
+        outer->nestedFunctions.append(f);
+    }
     return f;
 }
 
index b605e60..5f474f2 100644 (file)
--- a/qv4ir_p.h
+++ b/qv4ir_p.h
@@ -587,9 +587,11 @@ struct Ret: Stmt {
 struct Module {
     MemoryPool pool;
     QVector<Function *> functions;
+    Function *rootFunction;
 
-    Function *newFunction(const QString &name);
+    Function *newFunction(const QString &name, Function *outer);
 
+    Module() : rootFunction(0) {}
     ~Module();
 };
 
@@ -603,11 +605,11 @@ struct Function {
     QSet<QString> strings;
     QList<const QString *> formals;
     QList<const QString *> locals;
+    QVector<Function *> nestedFunctions;
 
     int insideWith;
 
     bool hasDirectEval: 1;
-    bool hasNestedFunctions: 1;
     bool isStrict: 1;
 
     template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
@@ -619,7 +621,6 @@ struct Function {
         , maxNumberOfArguments(0)
         , insideWith(0)
         , hasDirectEval(false)
-        , hasNestedFunctions(false)
         , isStrict(false)
     { this->name = newString(name); }
 
index cabd1f7..298d0b5 100644 (file)
@@ -381,7 +381,7 @@ InstructionSelection::~InstructionSelection()
     delete _asm;
 }
 
-VM::Function *InstructionSelection::run(IR::Function *function)
+void InstructionSelection::run(VM::Function *vmFunction, IR::Function *function)
 {
     qSwap(_function, function);
     Assembler* oldAssembler = _asm;
@@ -425,14 +425,11 @@ VM::Function *InstructionSelection::run(IR::Function *function)
 #endif
     _asm->ret();
 
-    VM::Function *vmFunc = vmFunction(_function);
-    _asm->link(vmFunc);
+    _asm->link(vmFunction);
 
     qSwap(_function, function);
     delete _asm;
     _asm = oldAssembler;
-
-    return vmFunc;
 }
 
 String *InstructionSelection::identifier(const QString &s)
index ca32511..481392c 100644 (file)
@@ -647,7 +647,7 @@ public:
     InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module);
     ~InstructionSelection();
 
-    virtual VM::Function *run(IR::Function *function);
+    virtual void run(VM::Function *vmFunction, IR::Function *function);
 
 protected:
     typedef Assembler::Address Address;
index 5a668fa..b49d4d3 100644 (file)
@@ -16,8 +16,10 @@ EvalInstructionSelection::EvalInstructionSelection(VM::ExecutionEngine *engine,
     assert(engine);
     assert(module);
 
-    foreach (IR::Function *f, module->functions)
-        _irToVM.insert(f, createFunctionMapping(engine, f));
+    createFunctionMapping(engine, module->rootFunction);
+    foreach (IR::Function *f, module->functions) {
+        assert(_irToVM.contains(f));
+    }
 }
 
 EvalInstructionSelection::~EvalInstructionSelection()
@@ -29,6 +31,8 @@ EvalISelFactory::~EvalISelFactory()
 VM::Function *EvalInstructionSelection::createFunctionMapping(VM::ExecutionEngine *engine, IR::Function *irFunction)
 {
     VM::Function *vmFunction = engine->newFunction(irFunction->name ? *irFunction->name : QString());
+    _irToVM.insert(irFunction, vmFunction);
+
     vmFunction->hasDirectEval = irFunction->hasDirectEval;
     vmFunction->isStrict = irFunction->isStrict;
 
@@ -39,8 +43,18 @@ VM::Function *EvalInstructionSelection::createFunctionMapping(VM::ExecutionEngin
         if (local)
             vmFunction->locals.append(*local);
 
+    foreach (IR::Function *function, irFunction->nestedFunctions)
+        vmFunction->nestedFunctions.append(createFunctionMapping(engine, function));
+
     if (engine->debugger)
         engine->debugger->mapFunction(vmFunction, irFunction);
 
     return vmFunction;
 }
+
+VM::Function *EvalInstructionSelection::vmFunction(IR::Function *f) {
+    VM::Function *function = _irToVM[f];
+    if (!function->code)
+        run(function, f);
+    return function;
+}
index 109ff79..221a564 100644 (file)
@@ -51,12 +51,12 @@ public:
     EvalInstructionSelection(VM::ExecutionEngine *engine, IR::Module *module);
     virtual ~EvalInstructionSelection() = 0;
 
-    virtual VM::Function *run(IR::Function *function) = 0;
+    VM::Function *vmFunction(IR::Function *f);
 
 protected:
     VM::Function *createFunctionMapping(VM::ExecutionEngine *engine, IR::Function *irFunction);
-    VM::Function *vmFunction(IR::Function *f) const { return _irToVM[f]; }
     VM::ExecutionEngine *engine() const { return _engine; }
+    virtual void run(VM::Function *vmFunction, IR::Function *function) = 0;
 
 private:
     VM::ExecutionEngine *_engine;