From 9edd6967753c16512c8c589f3dedcae02687070a Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 13 Dec 2012 12:09:04 +0100 Subject: [PATCH] Correctly set up nested functions 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 --- moth/qv4isel_moth.cpp | 32 ++++++++++++++++++++++---------- moth/qv4isel_moth_p.h | 2 +- qmljs_objects.cpp | 13 ++----------- qv4codegen.cpp | 4 ++-- qv4ecmaobjects.cpp | 2 +- qv4ir.cpp | 8 +++++++- qv4ir_p.h | 7 ++++--- qv4isel_masm.cpp | 7 ++----- qv4isel_masm_p.h | 2 +- qv4isel_p.cpp | 18 ++++++++++++++++-- qv4isel_p.h | 4 ++-- 11 files changed, 60 insertions(+), 39 deletions(-) diff --git a/moth/qv4isel_moth.cpp b/moth/qv4isel_moth.cpp index 5b00ccf..14fd1cb 100644 --- a/moth/qv4isel_moth.cpp +++ b/moth/qv4isel_moth.cpp @@ -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 > patches; + QHash 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) diff --git a/moth/qv4isel_moth_p.h b/moth/qv4isel_moth_p.h index e7c8517..dece413 100644 --- a/moth/qv4isel_moth_p.h +++ b/moth/qv4isel_moth_p.h @@ -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 *); diff --git a/qmljs_objects.cpp b/qmljs_objects.cpp index 8ab6e50..b282332 100644 --- a/qmljs_objects.cpp +++ b/qmljs_objects.cpp @@ -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 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) diff --git a/qv4codegen.cpp b/qv4codegen.cpp index 7409a54..1cbdc84 100644 --- a/qv4codegen.cpp +++ b/qv4codegen.cpp @@ -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; diff --git a/qv4ecmaobjects.cpp b/qv4ecmaobjects.cpp index 1a95c14..6bf661c 100644 --- a/qv4ecmaobjects.cpp +++ b/qv4ecmaobjects.cpp @@ -2058,7 +2058,7 @@ Value FunctionCtor::construct(ExecutionContext *ctx) IR::Function *irf = cg(QString(), fe, &module); QScopedPointer 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; diff --git a/qv4ir.cpp b/qv4ir.cpp index 33b8b77..8d4c4f8 100644 --- 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; } diff --git a/qv4ir_p.h b/qv4ir_p.h index b605e60..5f474f2 100644 --- a/qv4ir_p.h +++ b/qv4ir_p.h @@ -587,9 +587,11 @@ struct Ret: Stmt { struct Module { MemoryPool pool; QVector 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 strings; QList formals; QList locals; + QVector nestedFunctions; int insideWith; bool hasDirectEval: 1; - bool hasNestedFunctions: 1; bool isStrict: 1; template _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); } diff --git a/qv4isel_masm.cpp b/qv4isel_masm.cpp index cabd1f7..298d0b5 100644 --- a/qv4isel_masm.cpp +++ b/qv4isel_masm.cpp @@ -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) diff --git a/qv4isel_masm_p.h b/qv4isel_masm_p.h index ca32511..481392c 100644 --- a/qv4isel_masm_p.h +++ b/qv4isel_masm_p.h @@ -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; diff --git a/qv4isel_p.cpp b/qv4isel_p.cpp index 5a668fa..b49d4d3 100644 --- a/qv4isel_p.cpp +++ b/qv4isel_p.cpp @@ -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; +} diff --git a/qv4isel_p.h b/qv4isel_p.h index 109ff79..221a564 100644 --- a/qv4isel_p.h +++ b/qv4isel_p.h @@ -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; -- 2.7.4