Remove IR::Function from the runtime.
authorErik Verbruggen <erik.verbruggen@digia.com>
Tue, 11 Dec 2012 09:03:40 +0000 (10:03 +0100)
committerLars Knoll <lars.knoll@digia.com>
Tue, 11 Dec 2012 22:16:32 +0000 (23:16 +0100)
This fixes potential leaks of IR::Functions, lowers the memory usage
of the functions that the VM needs (because the IR fields are not
present in the VM::Function), and makes both managed by the module
respectively the ExecutionEngine.

Change-Id: I6748ad98b062f994eae9dd14f1919aec5aa7c0b0
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
19 files changed:
debugging.cpp
debugging.h
main.cpp
moth/qv4instr_moth_p.h
moth/qv4isel_moth.cpp
moth/qv4isel_moth_p.h
qmljs_engine.cpp
qmljs_engine.h
qmljs_objects.cpp
qmljs_objects.h
qmljs_runtime.cpp
qmljs_runtime.h
qv4ecmaobjects.cpp
qv4ir.cpp
qv4ir_p.h
qv4isel_masm.cpp
qv4isel_masm_p.h
qv4isel_p.cpp
qv4isel_p.h

index 62e38d0..4376d0a 100644 (file)
@@ -99,14 +99,14 @@ void Debugger::addFunction(IR::Function *function)
     _functionInfo.insert(function, new FunctionDebugInfo(function));
 }
 
-void Debugger::addaddBasicBlockOffset(IR::Function *function, IR::BasicBlock *block, ptrdiff_t blockOffset)
+void Debugger::setSourceLocation(IR::Function *function, unsigned line, unsigned column)
 {
-    _functionInfo[function]->addBasicBlockOffset(block, blockOffset);
+    _functionInfo[function]->setSourceLocation(line, column);
 }
 
-void Debugger::setSourceLocation(IR::Function *function, unsigned line, unsigned column)
+void Debugger::mapFunction(VM::Function *vmf, IR::Function *irf)
 {
-    _functionInfo[function]->setSourceLocation(line, column);
+    _vmToIr.insert(vmf, irf);
 }
 
 FunctionDebugInfo *Debugger::debugInfo(VM::FunctionObject *function) const
@@ -115,7 +115,7 @@ FunctionDebugInfo *Debugger::debugInfo(VM::FunctionObject *function) const
         return 0;
 
     if (VM::ScriptFunction *sf = function->asScriptFunction())
-        return _functionInfo[sf->function];
+        return _functionInfo[irFunction(sf->function)];
     else
         return 0;
 }
@@ -209,3 +209,8 @@ int Debugger::callIndex(VM::ExecutionContext *context)
 
     return -1;
 }
+
+IR::Function *Debugger::irFunction(VM::Function *vmf) const
+{
+    return _vmToIr[vmf];
+}
index 7c4c273..e283314 100644 (file)
@@ -48,14 +48,8 @@ class Debugger;
 
 struct FunctionDebugInfo { // TODO: use opaque d-pointers here
     IR::Function *function;
-    QHash<ptrdiff_t, IR::BasicBlock *> blockOffsets;
     unsigned startLine, startColumn;
-
-    FunctionDebugInfo(IR::Function *function): function(function), startLine(0), startColumn(0) {}
-
-    void addBasicBlockOffset(IR::BasicBlock *block, ptrdiff_t offset) {
-        blockOffsets.insert(offset, block);
-    }
+ FunctionDebugInfo(IR::Function *function): function(function), startLine(0), startColumn(0) {}
 
     void setSourceLocation(unsigned line, unsigned column)
     { startLine = line; startColumn = column; }
@@ -102,8 +96,8 @@ public:
 
 public: // compile-time interface
     void addFunction(IR::Function *function);
-    void addaddBasicBlockOffset(IR::Function *function, IR::BasicBlock *block, ptrdiff_t blockOffset);
     void setSourceLocation(IR::Function *function, unsigned line, unsigned column);
+    void mapFunction(VM::Function *vmf, IR::Function *irf);
 
 public: // run-time querying interface
     FunctionDebugInfo *debugInfo(VM::FunctionObject *function) const;
@@ -125,10 +119,12 @@ public: // debugging hooks
 
 private:
     int callIndex(VM::ExecutionContext *context);
+    IR::Function *irFunction(VM::Function *vmf) const;
 
 private: // TODO: use opaque d-pointers here
     VM::ExecutionEngine *_engine;
     QHash<IR::Function *, FunctionDebugInfo *> _functionInfo;
+    QHash<VM::Function *, IR::Function *> _vmToIr;
     QVector<CallInfo> _callStack;
 };
 
index 919cca7..7a79a7c 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -375,7 +375,7 @@ int main(int argc, char *argv[])
                     return EXIT_FAILURE;
                 }
 
-                QScopedPointer<QQmlJS::IR::Function> f(QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode));
+                QQmlJS::VM::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode);
                 if (!f)
                     continue;
 
index 67d1137..65a6a03 100644 (file)
@@ -86,7 +86,7 @@ union Instr
     };
     struct instr_loadClosure {
         MOTH_INSTR_HEADER
-        IR::Function *value;
+        VM::Function *value;
         int targetTempIndex;
     };
     struct instr_loadName {
index 10a5c11..328fdce 100644 (file)
@@ -181,27 +181,28 @@ private:
 
 } // anonymous namespace
 
-InstructionSelection::InstructionSelection(VM::ExecutionEngine *engine)
-    : _engine(engine)
+InstructionSelection::InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module)
+    : EvalInstructionSelection(engine, module)
+    , _function(0)
+    , _block(0)
+    , _code(0)
+    , _ccode(0)
 {
-    // FIXME: make the size dynamic. This requires changing the patching.
-    _code = new uchar[getpagesize() * 4000];
-    _ccode = _code;
 }
 
 InstructionSelection::~InstructionSelection()
 {
 }
 
-void InstructionSelection::operator()(IR::Function *function)
+VM::Function *InstructionSelection::run(IR::Function *function)
 {
     qSwap(_function, function);
+    // FIXME: make the size dynamic. This requires changing the patching.
+    _code = new uchar[getpagesize() * 4000];
+    _ccode = _code;
 
     CompressTemps().run(_function);
 
-    _function->code = VME::exec;
-    _function->codeData = _code;
-
     int locals = frameSize();
     assert(locals >= 0);
 
@@ -210,10 +211,7 @@ void InstructionSelection::operator()(IR::Function *function)
     addInstruction(push);
 
     foreach (_block, _function->basicBlocks) {
-        ptrdiff_t blockOffset = _ccode - _code;
         _addrs.insert(_block, _ccode - _code);
-        if (_engine->debugger)
-            _engine->debugger->addaddBasicBlockOffset(_function, _block, blockOffset);
 
         foreach (IR::Stmt *s, _block->statements)
             s->accept(this);
@@ -234,6 +232,17 @@ void InstructionSelection::operator()(IR::Function *function)
     }
 
     qSwap(_function, function);
+    _patches.clear();
+    _addrs.clear();
+
+    VM::Function *vmFunc = vmFunction(function);
+    vmFunc->code = VME::exec;
+    vmFunc->codeData = _code;
+
+    _block = 0;
+    _code = 0;
+    _ccode = 0;
+    return vmFunc;
 }
 
 void InstructionSelection::callActivationProperty(IR::Call *c, int targetTempIndex)
@@ -246,7 +255,7 @@ void InstructionSelection::callActivationProperty(IR::Call *c, int targetTempInd
         const int scratchIndex = scratchTempIndex();
 
         Instruction::LoadName load;
-        load.name = _engine->newString(*baseName->id);
+        load.name = engine()->newString(*baseName->id);
         load.targetTempIndex = scratchIndex;
         addInstruction(load);
 
@@ -272,7 +281,7 @@ void InstructionSelection::callActivationProperty(IR::Call *c, int targetTempInd
         if (IR::Member *m = c->args->expr->asMember()) {
             Instruction::CallBuiltinDeleteMember call;
             call.base = m->base->asTemp()->index;
-            call.member = _engine->newString(*m->name);
+            call.member = engine()->newString(*m->name);
             call.targetTempIndex = targetTempIndex;
             addInstruction(call);
         } else if (IR::Subscript *ss = c->args->expr->asSubscript()) {
@@ -283,7 +292,7 @@ void InstructionSelection::callActivationProperty(IR::Call *c, int targetTempInd
             addInstruction(call);
         } else if (IR::Name *n = c->args->expr->asName()) {
             Instruction::CallBuiltinDeleteName call;
-            call.name = _engine->newString(*n->id);
+            call.name = engine()->newString(*n->id);
             call.targetTempIndex = targetTempIndex;
             addInstruction(call);
         } else {
@@ -363,7 +372,7 @@ void InstructionSelection::callActivationProperty(IR::Call *c, int targetTempInd
         for (IR::ExprList *it = c->args->next; it; it = it->next) {
             Instruction::CallBuiltinDeclareVar call;
             call.isDeletable = isDeletable;
-            call.varName = _engine->newString(*it->expr->asName()->id);
+            call.varName = engine()->newString(*it->expr->asName()->id);
         }
     } break;
 
@@ -393,7 +402,7 @@ void InstructionSelection::callProperty(IR::Call *c, int targetTempIndex)
     // call the property on the loaded base
     Instruction::CallProperty call;
     call.baseTemp = m->base->asTemp()->index;
-    call.name = _engine->newString(*m->name);
+    call.name = engine()->newString(*m->name);
     prepareCallArgs(c->args, call.argc, call.args);
     call.targetTempIndex = targetTempIndex;
     addInstruction(call);
@@ -403,7 +412,7 @@ void InstructionSelection::construct(IR::New *ctor, int targetTempIndex)
 {
     if (IR::Name *baseName = ctor->base->asName()) {
         Instruction::CreateActivationProperty create;
-        create.name = _engine->newString(*baseName->id);
+        create.name = engine()->newString(*baseName->id);
         prepareCallArgs(ctor->args, create.argc, create.args);
         create.targetTempIndex = targetTempIndex;
         addInstruction(create);
@@ -413,7 +422,7 @@ void InstructionSelection::construct(IR::New *ctor, int targetTempIndex)
 
         Instruction::CreateProperty create;
         create.base = base->index;
-        create.name = _engine->newString(*member->name);
+        create.name = engine()->newString(*member->name);
         prepareCallArgs(ctor->args, create.argc, create.args);
         create.targetTempIndex = targetTempIndex;
         addInstruction(create);
@@ -578,7 +587,7 @@ void InstructionSelection::visitMove(IR::Move *s)
                 addInstruction(load);
             } else {
                 Instruction::LoadName load;
-                load.name = _engine->newString(*n->id);
+                load.name = engine()->newString(*n->id);
                 load.targetTempIndex = targetTempIndex;
                 addInstruction(load);
             }
@@ -607,12 +616,14 @@ void InstructionSelection::visitMove(IR::Move *s)
             }
         } else if (IR::String *str = s->source->asString()) {
             Instruction::LoadValue load;
-            load.value = VM::Value::fromString(_engine->newString(*str->value));
+            load.value = VM::Value::fromString(engine()->newString(*str->value));
             load.targetTempIndex = targetTempIndex;
             addInstruction(load);
         } else if (IR::Closure *clos = s->source->asClosure()) {
+            VM::Function *vmFunc = vmFunction(clos->value);
+            assert(vmFunc);
             Instruction::LoadClosure load;
-            load.value = clos->value;
+            load.value = vmFunc;
             load.targetTempIndex = targetTempIndex;
             addInstruction(load);
         } else if (IR::New *ctor = s->source->asNew()) {
@@ -621,7 +632,7 @@ void InstructionSelection::visitMove(IR::Move *s)
             if (IR::Temp *base = m->base->asTemp()) {
                 Instruction::LoadProperty load;
                 load.baseTemp = base->index;
-                load.name = _engine->newString(*m->name);
+                load.name = engine()->newString(*m->name);
                 load.targetTempIndex = targetTempIndex;
                 addInstruction(load);
             } else {
@@ -699,14 +710,14 @@ void InstructionSelection::visitMove(IR::Move *s)
             if (op) {
                 Instruction::InplaceNameOp ieo;
                 ieo.alu = op;
-                ieo.targetName = _engine->newString(*n->id);
+                ieo.targetName = engine()->newString(*n->id);
                 ieo.sourceIsTemp = toValueOrTemp(s->source, ieo.source);
                 addInstruction(ieo);
                 return;
             } else if (s->op == IR::OpInvalid) {
                 Instruction::StoreName store;
                 store.sourceIsTemp = toValueOrTemp(s->source, store.source);
-                store.name = _engine->newString(*n->id);
+                store.name = engine()->newString(*n->id);
                 addInstruction(store);
                 return;
             }
@@ -770,14 +781,14 @@ void InstructionSelection::visitMove(IR::Move *s)
                 Instruction::InplaceMemberOp imo;
                 imo.alu = op;
                 imo.targetBase = m->base->asTemp()->index;
-                imo.targetMember = _engine->newString(*m->name);
+                imo.targetMember = engine()->newString(*m->name);
                 imo.sourceIsTemp = toValueOrTemp(s->source, imo.source);
                 addInstruction(imo);
                 return;
             } else if (s->op == IR::OpInvalid) {
                 Instruction::StoreProperty store;
                 store.baseTemp = m->base->asTemp()->index;
-                store.name = _engine->newString(*m->name);
+                store.name = engine()->newString(*m->name);
                 store.sourceIsTemp = toValueOrTemp(s->source, store.source);
                 addInstruction(store);
                 return;
index 6fe5259..e7c8517 100644 (file)
@@ -12,12 +12,10 @@ namespace Moth {
 class InstructionSelection : public IR::StmtVisitor, public EvalInstructionSelection
 {
 public:
-    InstructionSelection(VM::ExecutionEngine *engine);
+    InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module);
     ~InstructionSelection();
 
-    virtual void run(IR::Function *function)
-    { this->operator()(function); }
-    virtual void operator()(IR::Function *function);
+    virtual VM::Function *run(IR::Function *function);
 
 protected:
     virtual void visitExp(IR::Exp *);
@@ -52,7 +50,6 @@ private:
     inline ptrdiff_t addInstruction(const InstrData<Instr> &data);
     ptrdiff_t addInstructionHelper(Instr::Type type, Instr &instr);
 
-    VM::ExecutionEngine *_engine;
     IR::Function *_function;
     IR::BasicBlock *_block;
 
@@ -67,8 +64,8 @@ class ISelFactory: public EvalISelFactory
 {
 public:
     virtual ~ISelFactory() {}
-    virtual EvalInstructionSelection *create(VM::ExecutionEngine *engine)
-    { return new InstructionSelection(engine); }
+    virtual EvalInstructionSelection *create(VM::ExecutionEngine *engine, IR::Module *module)
+    { return new InstructionSelection(engine, module); }
 };
 
 template<int InstrT>
index 4da9564..a29088f 100644 (file)
@@ -222,6 +222,7 @@ ExecutionEngine::~ExecutionEngine()
     delete globalObject.asObject();
     delete rootContext;
     delete stringPool;
+    qDeleteAll(functions);
 }
 
 ExecutionContext *ExecutionEngine::newContext()
@@ -237,6 +238,13 @@ String *ExecutionEngine::identifier(const QString &s)
     return id;
 }
 
+Function *ExecutionEngine::newFunction(const QString &name)
+{
+    VM::Function *f = new VM::Function(name);
+    functions.append(f);
+    return f;
+}
+
 FunctionObject *ExecutionEngine::newNativeFunction(ExecutionContext *scope, String *name, Value (*code)(ExecutionContext *))
 {
     NativeFunction *f = new (memoryManager) NativeFunction(scope, name, code);
@@ -244,8 +252,10 @@ FunctionObject *ExecutionEngine::newNativeFunction(ExecutionContext *scope, Stri
     return f;
 }
 
-FunctionObject *ExecutionEngine::newScriptFunction(ExecutionContext *scope, IR::Function *function)
+FunctionObject *ExecutionEngine::newScriptFunction(ExecutionContext *scope, VM::Function *function)
 {
+    assert(function);
+
     MemoryManager::GCBlocker gcBlocker(memoryManager);
 
     ScriptFunction *f = new (memoryManager) ScriptFunction(scope, function);
index 1b4e593..eef62a3 100644 (file)
@@ -56,6 +56,7 @@ namespace VM {
 
 struct Value;
 class Array;
+struct Function;
 struct Object;
 struct BooleanObject;
 struct NumberObject;
@@ -156,6 +157,7 @@ struct ExecutionEngine
     Value exception;
 
     struct StringPool *stringPool;
+    QVector<Function *> functions;
 
     ExecutionEngine(MemoryManager *memoryManager, EvalISelFactory *iselFactory);
     ~ExecutionEngine();
@@ -164,8 +166,10 @@ struct ExecutionEngine
 
     String *identifier(const QString &s);
 
+    VM::Function *newFunction(const QString &name);
+
     FunctionObject *newNativeFunction(ExecutionContext *scope, String *name, Value (*code)(ExecutionContext *));
-    FunctionObject *newScriptFunction(ExecutionContext *scope, IR::Function *function);
+    FunctionObject *newScriptFunction(ExecutionContext *scope, VM::Function *function);
 
     Object *newObject();
     FunctionObject *newObjectCtor(ExecutionContext *ctx);
index c3aafae..431d508 100644 (file)
@@ -426,6 +426,11 @@ void ArrayObject::getCollectables(QVector<Object *> &objects)
     value.getCollectables(objects);
 }
 
+Function::~Function()
+{
+    delete[] codeData;
+}
+
 bool FunctionObject::hasInstance(ExecutionContext *ctx, const Value &value)
 {
     if (! value.isObject()) {
@@ -489,23 +494,26 @@ Value FunctionObject::construct(ExecutionContext *ctx)
     return ctx->thisObject;
 }
 
-ScriptFunction::ScriptFunction(ExecutionContext *scope, IR::Function *function)
+ScriptFunction::ScriptFunction(ExecutionContext *scope, VM::Function *function)
     : FunctionObject(scope)
     , function(function)
 {
+    assert(function);
+    assert(function->code);
+
     // global function
     if (!scope)
         return;
 
-    if (function->name)
-        name = scope->engine->identifier(*function->name);
+    if (!function->name.isEmpty())
+        name = scope->engine->identifier(function->name);
     needsActivation = function->needsActivation();
     strictMode = function->isStrict;
     formalParameterCount = function->formals.size();
     if (formalParameterCount) {
         formalParameterList = new String*[formalParameterCount];
         for (unsigned int i = 0; i < formalParameterCount; ++i) {
-            formalParameterList[i] = scope->engine->identifier(*function->formals.at(i));
+            formalParameterList[i] = scope->engine->identifier(function->formals.at(i));
         }
     }
 
@@ -513,7 +521,7 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, IR::Function *function)
     if (varCount) {
         varList = new String*[varCount];
         for (unsigned int i = 0; i < varCount; ++i) {
-            varList[i] = scope->engine->identifier(*function->locals.at(i));
+            varList[i] = scope->engine->identifier(function->locals.at(i));
         }
     }
 }
@@ -526,6 +534,7 @@ ScriptFunction::~ScriptFunction()
 
 Value ScriptFunction::call(VM::ExecutionContext *ctx)
 {
+    assert(function->code);
     return function->code(ctx, function->codeData);
 }
 
@@ -542,7 +551,7 @@ Value EvalFunction::call(ExecutionContext *context, Value /*thisObject*/, Value
     bool directCall = true;
 
     const QString code = args[0].stringValue()->toQString();
-    QScopedPointer<QQmlJS::IR::Function> f(parseSource(context, QStringLiteral("eval code"), code, QQmlJS::Codegen::EvalCode));
+    QQmlJS::VM::Function *f = parseSource(context, QStringLiteral("eval code"), code, QQmlJS::Codegen::EvalCode);
     if (!f)
         return Value::undefinedValue();
 
@@ -580,7 +589,7 @@ EvalFunction::EvalFunction(ExecutionContext *scope)
     name = scope->engine->newString(QLatin1String("eval"));
 }
 
-QQmlJS::IR::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ctx,
+QQmlJS::VM::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ctx,
                                                 const QString &fileName, const QString &source,
                                                 QQmlJS::Codegen::Mode mode)
 {
@@ -590,7 +599,7 @@ QQmlJS::IR::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ct
 
     VM::ExecutionEngine *vm = ctx->engine;
     IR::Module module;
-    IR::Function *globalCode = 0;
+    VM::Function *globalCode = 0;
 
     {
         QQmlJS::Engine ee, *engine = &ee;
@@ -630,13 +639,17 @@ QQmlJS::IR::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ct
             }
 
             Codegen cg(ctx);
-            globalCode = cg(fileName, program, &module, mode);
+            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) {
-                    EvalInstructionSelection *isel = ctx->engine->iselFactory->create(vm);
-                    isel->run(function);
-                    delete isel;
+                    if (function == globalIRCode)
+                        continue;
+                    globalCode->nestedFunctions.append(isel->run(function));
                 }
             }
         }
index 51127f6..1b0b67f 100644 (file)
 
 namespace QQmlJS {
 
-namespace IR {
-struct Function;
-}
-
 namespace VM {
 
 struct Value;
+struct Function;
 struct Object;
 struct BooleanObject;
 struct NumberObject;
@@ -525,6 +522,34 @@ protected:
     virtual void getCollectables(QVector<Object *> &objects);
 };
 
+struct Function {
+    QString name;
+
+    VM::Value (*code)(VM::ExecutionContext *, const uchar *);
+    const uchar *codeData;
+    JSC::MacroAssemblerCodeRef codeRef;
+
+    QList<QString> formals;
+    QList<QString> locals;
+    QVector<Function *> nestedFunctions;
+
+    bool hasDirectEval: 1;
+    bool isStrict: 1;
+
+    Function(const QString &name)
+        : name(name)
+        , code(0)
+        , codeData(0)
+        , hasDirectEval(false)
+        , isStrict(false)
+    {}
+    ~Function();
+
+    inline bool hasNestedFunctions() const { return !nestedFunctions.isEmpty(); }
+
+    inline bool needsActivation() const { return hasNestedFunctions() || hasDirectEval; }
+};
+
 struct FunctionObject: Object {
     ExecutionContext *scope;
     String *name;
@@ -568,9 +593,9 @@ struct NativeFunction: FunctionObject {
 };
 
 struct ScriptFunction: FunctionObject {
-    IR::Function *function;
+    VM::Function *function;
 
-    ScriptFunction(ExecutionContext *scope, IR::Function *function);
+    ScriptFunction(ExecutionContext *scope, VM::Function *function);
     virtual ~ScriptFunction();
 
     virtual Value call(ExecutionContext *ctx);
@@ -583,9 +608,10 @@ struct EvalFunction : FunctionObject
 {
     EvalFunction(ExecutionContext *scope);
 
-    static QQmlJS::IR::Function *parseSource(QQmlJS::VM::ExecutionContext *ctx,
-                                     const QString &fileName, const QString &source,
-                                     QQmlJS::Codegen::Mode mode);
+    static QQmlJS::VM::Function *parseSource(QQmlJS::VM::ExecutionContext *ctx,
+                                             const QString &fileName,
+                                             const QString &source,
+                                             QQmlJS::Codegen::Mode mode);
 
     virtual Value call(ExecutionContext *context, Value thisObject, Value *args, int argc);
 };
index 1e664d2..a00ac6c 100644 (file)
@@ -105,8 +105,9 @@ QString numberToString(double num, int radix = 10)
 
 extern "C" {
 
-Value __qmljs_init_closure(IR::Function *clos, ExecutionContext *ctx)
+Value __qmljs_init_closure(VM::Function *clos, ExecutionContext *ctx)
 {
+    assert(clos);
     return Value::fromObject(ctx->engine->newScriptFunction(ctx, clos));
 }
 
index e8049d9..1021d4e 100644 (file)
 #endif // TRACE1
 
 namespace QQmlJS {
-
-namespace IR {
-struct Function;
-}
-
 namespace VM {
 
 enum TypeHint {
@@ -73,6 +68,7 @@ enum TypeHint {
     STRING_HINT
 };
 
+struct Function;
 struct Object;
 struct String;
 struct PropertyDescriptor;
@@ -109,7 +105,7 @@ void __qmljs_builtin_pop_with(ExecutionContext *ctx);
 void __qmljs_builtin_declare_var(ExecutionContext *ctx, bool deletable, String *name);
 
 // constructors
-Value __qmljs_init_closure(IR::Function *clos, ExecutionContext *ctx);
+Value __qmljs_init_closure(VM::Function *clos, ExecutionContext *ctx);
 Value __qmljs_init_native_function(String *name, Value (*code)(ExecutionContext *), ExecutionContext *ctx);
 
 Bool __qmljs_is_function(Value value);
index c9b9593..fb3f6d7 100644 (file)
@@ -2040,11 +2040,10 @@ Value FunctionCtor::construct(ExecutionContext *ctx)
     Codegen cg(ctx);
     IR::Function *irf = cg(QString(), fe, &module);
 
-    EvalInstructionSelection *isel = ctx->engine->iselFactory->create(ctx->engine);
-    isel->run(irf);
-    delete isel;
+    QScopedPointer<EvalInstructionSelection> isel(ctx->engine->iselFactory->create(ctx->engine, &module));
+    VM::Function *vmf = isel->run(irf);
 
-    ctx->thisObject = Value::fromObject(ctx->engine->newScriptFunction(ctx->engine->rootContext, irf));
+    ctx->thisObject = Value::fromObject(ctx->engine->newScriptFunction(ctx->engine->rootContext, vmf));
     return ctx->thisObject;
 }
 
index 2a9414b..3cceeb8 100644 (file)
--- a/qv4ir.cpp
+++ b/qv4ir.cpp
@@ -393,18 +393,13 @@ Function *Module::newFunction(const QString &name)
 
 Module::~Module()
 {
-    foreach (Function *f, functions)
-        f->releaseModuleManagedData();
+    foreach (Function *f, functions) {
+        delete f;
+    }
 }
 
 Function::~Function()
 {
-    delete[] codeData;
-}
-
-
-void Function::releaseModuleManagedData()
-{
     // destroy the Stmt::Data blocks manually, because memory pool cleanup won't
     // call the Stmt destructors.
     foreach (IR::BasicBlock *b, basicBlocks)
index 14c73e5..c6d05d2 100644 (file)
--- a/qv4ir_p.h
+++ b/qv4ir_p.h
@@ -602,10 +602,6 @@ struct Function {
     QList<const QString *> formals;
     QList<const QString *> locals;
 
-    VM::Value (*code)(VM::ExecutionContext *, const uchar *);
-    const uchar *codeData;
-    JSC::MacroAssemblerCodeRef codeRef;
-
     int insideWith;
 
     bool hasDirectEval: 1;
@@ -619,8 +615,6 @@ struct Function {
         , pool(&module->pool)
         , tempCount(0)
         , maxNumberOfArguments(0)
-        , code(0)
-        , codeData(0)
         , insideWith(0)
         , hasDirectEval(false)
         , hasNestedFunctions(false)
@@ -628,7 +622,6 @@ struct Function {
     { this->name = newString(name); }
 
     ~Function();
-    void releaseModuleManagedData();
 
     enum BasicBlockInsertMode {
         InsertBlock,
@@ -644,8 +637,6 @@ struct Function {
     inline BasicBlock *insertBasicBlock(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 {
index bcd7585..d107a6b 100644 (file)
@@ -313,7 +313,7 @@ static void printDisassembledOutputWithCalls(const char* output, const QHash<voi
 }
 #endif
 
-void Assembler::link()
+void Assembler::link(VM::Function *vmFunc)
 {
     QHashIterator<IR::BasicBlock *, QVector<Jump> > it(_patches);
     while (it.hasNext()) {
@@ -343,7 +343,7 @@ void Assembler::link()
 #endif
 
         QByteArray name = _function->name->toUtf8();
-        _function->codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
+        vmFunc->codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
 
         WTF::setDataFile(stderr);
 #if OS(LINUX)
@@ -354,14 +354,14 @@ void Assembler::link()
         free(disasmOutput);
 #endif
     } else {
-        _function->codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
+        vmFunc->codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
     }
 
-    _function->code = (Value (*)(VM::ExecutionContext *, const uchar *)) _function->codeRef.code().executableAddress();
+    vmFunc->code = (Value (*)(VM::ExecutionContext *, const uchar *)) vmFunc->codeRef.code().executableAddress();
 }
 
-InstructionSelection::InstructionSelection(VM::ExecutionEngine *engine)
-    : _engine(engine)
+InstructionSelection::InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module)
+    : EvalInstructionSelection(engine, module)
     , _block(0)
     , _function(0)
     , _asm(0)
@@ -373,7 +373,7 @@ InstructionSelection::~InstructionSelection()
     delete _asm;
 }
 
-void InstructionSelection::operator()(IR::Function *function)
+VM::Function *InstructionSelection::run(IR::Function *function)
 {
     qSwap(_function, function);
     Assembler* oldAssembler = _asm;
@@ -417,16 +417,19 @@ void InstructionSelection::operator()(IR::Function *function)
 #endif
     _asm->ret();
 
-    _asm->link();
+    VM::Function *vmFunc = vmFunction(_function);
+    _asm->link(vmFunc);
 
     qSwap(_function, function);
     delete _asm;
     _asm = oldAssembler;
+
+    return vmFunc;
 }
 
 String *InstructionSelection::identifier(const QString &s)
 {
-    return _engine->identifier(s);
+    return engine()->identifier(s);
 }
 
 void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *result)
@@ -662,16 +665,18 @@ void InstructionSelection::visitMove(IR::Move *s)
                 return;
             } else if (IR::String *str = s->source->asString()) {
                 Address dest = _asm->loadTempAddress(Assembler::ScratchRegister, t);
-                Value v = Value::fromString(_engine->newString(*str->value));
+                Value v = Value::fromString(engine()->newString(*str->value));
                 _asm->storeValue(v, dest);
                 return;
             } else if (IR::RegExp *re = s->source->asRegExp()) {
                 Address dest = _asm->loadTempAddress(Assembler::ScratchRegister, t);
-                Value v = Value::fromObject(_engine->newRegExpObject(*re->value, re->flags));
+                Value v = Value::fromObject(engine()->newRegExpObject(*re->value, re->flags));
                 _asm->storeValue(v, dest);
                 return;
             } else if (IR::Closure *clos = s->source->asClosure()) {
-                generateFunctionCall(t, __qmljs_init_closure, Assembler::TrustedImmPtr(clos->value), Assembler::ContextRegister);
+                VM::Function *vmFunc = vmFunction(clos->value);
+                assert(vmFunc);
+                generateFunctionCall(t, __qmljs_init_closure, Assembler::TrustedImmPtr(vmFunc), Assembler::ContextRegister);
                 return;
             } else if (IR::New *ctor = s->source->asNew()) {
                 if (ctor->base->asName()) {
index 7a478ae..243b066 100644 (file)
@@ -630,7 +630,7 @@ public:
         return Jump();
     }
 
-    void link();
+    void link(VM::Function *vmFunc);
 
 private:
     IR::Function* _function;
@@ -642,12 +642,10 @@ private:
 class InstructionSelection: protected IR::StmtVisitor, public EvalInstructionSelection
 {
 public:
-    InstructionSelection(VM::ExecutionEngine *engine);
+    InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module);
     ~InstructionSelection();
 
-    virtual void run(IR::Function *function)
-    { this->operator()(function); }
-    void operator()(IR::Function *function);
+    virtual VM::Function *run(IR::Function *function);
 
 protected:
     typedef Assembler::Address Address;
@@ -710,8 +708,6 @@ private:
 #define callRuntimeMethod(result, function, ...) \
     callRuntimeMethodImp(result, isel_stringIfy(function), function, __VA_ARGS__)
 
-
-    VM::ExecutionEngine *_engine;
     IR::BasicBlock *_block;
     IR::Function* _function;
     Assembler* _asm;
@@ -721,8 +717,8 @@ class ISelFactory: public EvalISelFactory
 {
 public:
     virtual ~ISelFactory() {}
-    virtual EvalInstructionSelection *create(VM::ExecutionEngine *engine)
-    { return new InstructionSelection(engine); }
+    virtual EvalInstructionSelection *create(VM::ExecutionEngine *engine, IR::Module *module)
+    { return new InstructionSelection(engine, module); }
 };
 
 } // end of namespace MASM
index 175cea5..5a668fa 100644 (file)
@@ -1,9 +1,46 @@
+#include "debugging.h"
+#include "qmljs_engine.h"
+#include "qv4ir_p.h"
 #include "qv4isel_p.h"
+#include "qv4isel_util_p.h"
+
+#include <QString>
+
+#include <cassert>
 
 using namespace QQmlJS;
 
+EvalInstructionSelection::EvalInstructionSelection(VM::ExecutionEngine *engine, IR::Module *module)
+    : _engine(engine)
+{
+    assert(engine);
+    assert(module);
+
+    foreach (IR::Function *f, module->functions)
+        _irToVM.insert(f, createFunctionMapping(engine, f));
+}
+
 EvalInstructionSelection::~EvalInstructionSelection()
 {}
 
 EvalISelFactory::~EvalISelFactory()
 {}
+
+VM::Function *EvalInstructionSelection::createFunctionMapping(VM::ExecutionEngine *engine, IR::Function *irFunction)
+{
+    VM::Function *vmFunction = engine->newFunction(irFunction->name ? *irFunction->name : QString());
+    vmFunction->hasDirectEval = irFunction->hasDirectEval;
+    vmFunction->isStrict = irFunction->isStrict;
+
+    foreach (const QString *formal, irFunction->formals)
+        if (formal)
+            vmFunction->formals.append(*formal);
+    foreach (const QString *local, irFunction->locals)
+        if (local)
+            vmFunction->locals.append(*local);
+
+    if (engine->debugger)
+        engine->debugger->mapFunction(vmFunction, irFunction);
+
+    return vmFunction;
+}
index e8c6d38..109ff79 100644 (file)
@@ -31,6 +31,7 @@
 #define QV4ISEL_P_H
 
 #include <qglobal.h>
+#include <QHash>
 
 namespace QQmlJS {
 
@@ -41,21 +42,32 @@ struct Module;
 
 namespace VM {
 struct ExecutionEngine;
+struct Function;
 } // namespace VM
 
 class EvalInstructionSelection
 {
 public:
+    EvalInstructionSelection(VM::ExecutionEngine *engine, IR::Module *module);
     virtual ~EvalInstructionSelection() = 0;
 
-    virtual void run(IR::Function *function) = 0;
+    virtual VM::Function *run(IR::Function *function) = 0;
+
+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; }
+
+private:
+    VM::ExecutionEngine *_engine;
+    QHash<IR::Function *, VM::Function *> _irToVM;
 };
 
 class EvalISelFactory
 {
 public:
     virtual ~EvalISelFactory() = 0;
-    virtual EvalInstructionSelection *create(VM::ExecutionEngine *engine) = 0;
+    virtual EvalInstructionSelection *create(VM::ExecutionEngine *engine, IR::Module *module) = 0;
 };
 
 } // namespace QQmlJS